Advertisement
Guest User

Untitled

a guest
Jun 5th, 2016
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 147.91 KB | None | 0 0
  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.  
  35. /* STUN server/port, if any */
  36. static char *janus_stun_server = NULL;
  37. static uint16_t janus_stun_port = 0;
  38.  
  39. char *janus_ice_get_stun_server(void) {
  40. return janus_stun_server;
  41. }
  42. uint16_t janus_ice_get_stun_port(void) {
  43. return janus_stun_port;
  44. }
  45.  
  46.  
  47. /* TURN server/port and credentials, if any */
  48. static char *janus_turn_server = NULL;
  49. static uint16_t janus_turn_port = 0;
  50. static char *janus_turn_user = NULL, *janus_turn_pwd = NULL;
  51. static NiceRelayType janus_turn_type = NICE_RELAY_TYPE_TURN_UDP;
  52.  
  53. char *janus_ice_get_turn_server(void) {
  54. return janus_turn_server;
  55. }
  56. uint16_t janus_ice_get_turn_port(void) {
  57. return janus_turn_port;
  58. }
  59.  
  60.  
  61. /* TURN REST API support, if any */
  62. char *janus_ice_get_turn_rest_api(void) {
  63. #ifndef HAVE_LIBCURL
  64. return NULL;
  65. #else
  66. return (char *)janus_turnrest_get_backend();
  67. #endif
  68. }
  69.  
  70.  
  71. /* ICE-Lite status */
  72. static gboolean janus_ice_lite_enabled;
  73. gboolean janus_ice_is_ice_lite_enabled(void) {
  74. return janus_ice_lite_enabled;
  75. }
  76.  
  77. /* ICE-TCP support (only libnice >= 0.1.8, currently broken) */
  78. static gboolean janus_ice_tcp_enabled;
  79. gboolean janus_ice_is_ice_tcp_enabled(void) {
  80. return janus_ice_tcp_enabled;
  81. }
  82.  
  83. /* IPv6 support (still mostly WIP) */
  84. static gboolean janus_ipv6_enabled;
  85. gboolean janus_ice_is_ipv6_enabled(void) {
  86. return janus_ipv6_enabled;
  87. }
  88.  
  89. /* Whether BUNDLE support is mandatory or not (false by default) */
  90. static gboolean janus_force_bundle;
  91. void janus_ice_force_bundle(gboolean forced) {
  92. janus_force_bundle = forced;
  93. JANUS_LOG(LOG_INFO, "BUNDLE %s going to be forced\n", janus_force_bundle ? "is" : "is NOT");
  94. }
  95. gboolean janus_ice_is_bundle_forced(void) {
  96. return janus_force_bundle;
  97. }
  98.  
  99. /* Whether rtcp-mux support is mandatory or not (false by default) */
  100. static gboolean janus_force_rtcpmux;
  101. static gint janus_force_rtcpmux_blackhole_port = 1234;
  102. static gint janus_force_rtcpmux_blackhole_fd = 0;
  103. void janus_ice_force_rtcpmux(gboolean forced) {
  104. janus_force_rtcpmux = forced;
  105. JANUS_LOG(LOG_INFO, "rtcp-mux %s going to be forced\n", janus_force_rtcpmux ? "is" : "is NOT");
  106. if(!janus_force_rtcpmux) {
  107. /*
  108. * Since rtcp-mux is NOT going to be forced, we need to do some magic to get rid of unneeded
  109. * RTCP components when rtcp-mux is indeed negotiated when creating a PeerConnection. In
  110. * particular, there's no way to remove a component in libnice (you can only remove streams),
  111. * and you can read why this is a problem here:
  112. * https://github.com/meetecho/janus-gateway/issues/154
  113. * https://github.com/meetecho/janus-gateway/pull/362
  114. * This means that, to effectively do that without just ignoring the component, we need
  115. * to set a dummy candidate on it to "trick" libnice into thinking ICE is done for it.
  116. * Since libnice will still occasionally send keepalives to the dummy peer, and we don't
  117. * want it to send messages to a service that might not like it, we create a "blackhole"
  118. * UDP server to receive all those keepalives and then just discard them.
  119. */
  120. int blackhole = socket(AF_INET, SOCK_DGRAM, 0);
  121. if(blackhole < 0) {
  122. JANUS_LOG(LOG_WARN, "Error creating RTCP component blackhole socket, using port %d instead\n", janus_force_rtcpmux_blackhole_port);
  123. return;
  124. }
  125. fcntl(blackhole, F_SETFL, O_NONBLOCK);
  126. struct sockaddr_in serveraddr;
  127. serveraddr.sin_family = AF_INET;
  128. serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
  129. serveraddr.sin_port = htons(0); /* Choose a random port, that works for us */
  130. if(bind(blackhole, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) {
  131. JANUS_LOG(LOG_WARN, "Error binding RTCP component blackhole socket, using port %d instead\n", janus_force_rtcpmux_blackhole_port);
  132. return;
  133. }
  134. socklen_t len = sizeof(serveraddr);
  135. if(getsockname(blackhole, (struct sockaddr *)&serveraddr, &len) < 0) {
  136. JANUS_LOG(LOG_WARN, "Error retrieving port assigned to RTCP component blackhole socket, using port %d instead\n", janus_force_rtcpmux_blackhole_port);
  137. return;
  138. }
  139. janus_force_rtcpmux_blackhole_port = ntohs(serveraddr.sin_port);
  140. JANUS_LOG(LOG_VERB, " -- RTCP component blackhole socket bound to port %d\n", janus_force_rtcpmux_blackhole_port);
  141. janus_force_rtcpmux_blackhole_fd = blackhole;
  142.  
  143. }
  144. }
  145. gint janus_ice_get_rtcpmux_blackhole_port(void) {
  146. return janus_force_rtcpmux_blackhole_port;
  147. }
  148. gboolean janus_ice_is_rtcpmux_forced(void) {
  149. return janus_force_rtcpmux;
  150. }
  151.  
  152.  
  153. /* libnice debugging */
  154. static gboolean janus_ice_debugging_enabled;
  155. gboolean janus_ice_is_ice_debugging_enabled(void) {
  156. return janus_ice_debugging_enabled;
  157. }
  158. void janus_ice_debugging_enable(void) {
  159. JANUS_LOG(LOG_VERB, "Enabling libnice debugging...\n");
  160. if(g_getenv("NICE_DEBUG") == NULL) {
  161. JANUS_LOG(LOG_WARN, "No NICE_DEBUG environment variable set, setting maximum debug\n");
  162. g_setenv("NICE_DEBUG", "all", TRUE);
  163. }
  164. if(g_getenv("G_MESSAGES_DEBUG") == NULL) {
  165. JANUS_LOG(LOG_WARN, "No G_MESSAGES_DEBUG environment variable set, setting maximum debug\n");
  166. g_setenv("G_MESSAGES_DEBUG", "all", TRUE);
  167. }
  168. JANUS_LOG(LOG_VERB, "Debugging NICE_DEBUG=%s G_MESSAGES_DEBUG=%s\n",
  169. g_getenv("NICE_DEBUG"), g_getenv("G_MESSAGES_DEBUG"));
  170. janus_ice_debugging_enabled = TRUE;
  171. nice_debug_enable(strstr(g_getenv("NICE_DEBUG"), "all") || strstr(g_getenv("NICE_DEBUG"), "stun"));
  172. }
  173. void janus_ice_debugging_disable(void) {
  174. JANUS_LOG(LOG_VERB, "Disabling libnice debugging...\n");
  175. janus_ice_debugging_enabled = FALSE;
  176. nice_debug_disable(TRUE);
  177. }
  178.  
  179.  
  180. /* NAT 1:1 stuff */
  181. static gboolean nat_1_1_enabled = FALSE;
  182. void janus_ice_enable_nat_1_1(void) {
  183. nat_1_1_enabled = TRUE;
  184. }
  185.  
  186. /* Interface/IP enforce/ignore lists */
  187. GList *janus_ice_enforce_list = NULL, *janus_ice_ignore_list = NULL;
  188. janus_mutex ice_list_mutex;
  189.  
  190. void janus_ice_enforce_interface(const char *ip) {
  191. if(ip == NULL)
  192. return;
  193. /* Is this an IP or an interface? */
  194. janus_mutex_lock(&ice_list_mutex);
  195. janus_ice_enforce_list = g_list_append(janus_ice_enforce_list, (gpointer)ip);
  196. janus_mutex_unlock(&ice_list_mutex);
  197. }
  198. gboolean janus_ice_is_enforced(const char *ip) {
  199. if(ip == NULL || janus_ice_enforce_list == NULL)
  200. return false;
  201. janus_mutex_lock(&ice_list_mutex);
  202. GList *temp = janus_ice_enforce_list;
  203. while(temp) {
  204. const char *enforced = (const char *)temp->data;
  205. if(enforced != NULL && strstr(ip, enforced)) {
  206. janus_mutex_unlock(&ice_list_mutex);
  207. return true;
  208. }
  209. temp = temp->next;
  210. }
  211. janus_mutex_unlock(&ice_list_mutex);
  212. return false;
  213. }
  214.  
  215. void janus_ice_ignore_interface(const char *ip) {
  216. if(ip == NULL)
  217. return;
  218. /* Is this an IP or an interface? */
  219. janus_mutex_lock(&ice_list_mutex);
  220. janus_ice_ignore_list = g_list_append(janus_ice_ignore_list, (gpointer)ip);
  221. if(janus_ice_enforce_list != NULL) {
  222. 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);
  223. }
  224. janus_mutex_unlock(&ice_list_mutex);
  225. }
  226. gboolean janus_ice_is_ignored(const char *ip) {
  227. if(ip == NULL || janus_ice_ignore_list == NULL)
  228. return false;
  229. janus_mutex_lock(&ice_list_mutex);
  230. GList *temp = janus_ice_ignore_list;
  231. while(temp) {
  232. const char *ignored = (const char *)temp->data;
  233. if(ignored != NULL && strstr(ip, ignored)) {
  234. janus_mutex_unlock(&ice_list_mutex);
  235. return true;
  236. }
  237. temp = temp->next;
  238. }
  239. janus_mutex_unlock(&ice_list_mutex);
  240. return false;
  241. }
  242.  
  243.  
  244. /* RTP/RTCP port range */
  245. uint16_t rtp_range_min = 0;
  246. uint16_t rtp_range_max = 0;
  247.  
  248.  
  249. /* Helpers to demultiplex protocols */
  250. gboolean janus_is_dtls(gchar *buf);
  251. gboolean janus_is_dtls(gchar *buf) {
  252. return ((*buf >= 20) && (*buf <= 64));
  253. }
  254.  
  255. gboolean janus_is_rtp(gchar *buf);
  256. gboolean janus_is_rtp(gchar *buf) {
  257. rtp_header *header = (rtp_header *)buf;
  258. return ((header->type < 64) || (header->type >= 96));
  259. }
  260.  
  261. gboolean janus_is_rtcp(gchar *buf);
  262. gboolean janus_is_rtcp(gchar *buf) {
  263. rtp_header *header = (rtp_header *)buf;
  264. return ((header->type >= 64) && (header->type < 96));
  265. }
  266.  
  267.  
  268. #define JANUS_ICE_PACKET_AUDIO 0
  269. #define JANUS_ICE_PACKET_VIDEO 1
  270. #define JANUS_ICE_PACKET_DATA 2
  271. /* Janus enqueued (S)RTP/(S)RTCP packet to send */
  272. typedef struct janus_ice_queued_packet {
  273. char *data;
  274. gint length;
  275. gint type;
  276. gboolean control;
  277. gboolean encrypted;
  278. } janus_ice_queued_packet;
  279. /* This is a static, fake, message we use as a trigger to send a DTLS alert */
  280. static janus_ice_queued_packet janus_ice_dtls_alert;
  281.  
  282.  
  283. /* Maximum value, in milliseconds, for the NACK queue/retransmissions (default=1000ms=1s) */
  284. #define DEFAULT_MAX_NACK_QUEUE 1000
  285. /* Maximum ignore count after retransmission (100ms) */
  286. #define MAX_NACK_IGNORE 100000
  287.  
  288. static uint max_nack_queue = DEFAULT_MAX_NACK_QUEUE;
  289. void janus_set_max_nack_queue(uint mnq) {
  290. max_nack_queue = mnq;
  291. if(max_nack_queue == 0)
  292. JANUS_LOG(LOG_VERB, "Disabling NACK queue\n");
  293. else
  294. JANUS_LOG(LOG_VERB, "Setting max NACK queue to %ds\n", max_nack_queue);
  295. }
  296. uint janus_get_max_nack_queue(void) {
  297. return max_nack_queue;
  298. }
  299. /* Helper to clean old NACK packets in the buffer when they exceed the queue time limit */
  300. static void janus_cleanup_nack_buffer(gint64 now, janus_ice_stream *stream) {
  301. if(stream && stream->rtp_component) {
  302. janus_ice_component *component = stream->rtp_component;
  303. janus_mutex_lock(&component->mutex);
  304. if(component->retransmit_buffer) {
  305. GList *first = g_list_first(component->retransmit_buffer);
  306. janus_rtp_packet *p = (janus_rtp_packet *)first->data;
  307. while(p && (now - p->created >= max_nack_queue*1000)) {
  308. /* Packet is too old, get rid of it */
  309. first->data = NULL;
  310. component->retransmit_buffer = g_list_delete_link(component->retransmit_buffer, first);
  311. g_free(p->data);
  312. p->data = NULL;
  313. g_free(p);
  314. first = g_list_first(component->retransmit_buffer);
  315. p = (janus_rtp_packet *)(first ? first->data : NULL);
  316. }
  317. }
  318. janus_mutex_unlock(&component->mutex);
  319. }
  320. }
  321.  
  322.  
  323. #define SEQ_MISSING_WAIT 12000 /* 12ms */
  324. #define SEQ_NACKED_WAIT 155000 /* 155ms */
  325. /* seq_info_t list functions */
  326. static void janus_seq_append(seq_info_t **head, seq_info_t *new_seq) {
  327. if(*head == NULL) {
  328. new_seq->prev = new_seq;
  329. new_seq->next = new_seq;
  330. *head = new_seq;
  331. } else {
  332. seq_info_t *last_seq = (*head)->prev;
  333. new_seq->prev = last_seq;
  334. new_seq->next = *head;
  335. (*head)->prev = new_seq;
  336. last_seq->next = new_seq;
  337. }
  338. }
  339. static seq_info_t *janus_seq_pop_head(seq_info_t **head) {
  340. seq_info_t *pop_seq = *head;
  341. if(pop_seq) {
  342. seq_info_t *new_head = pop_seq->next;
  343. if (pop_seq == new_head) {
  344. *head = NULL;
  345. } else {
  346. *head = new_head;
  347. new_head->prev = pop_seq->prev;
  348. new_head->prev->next = new_head;
  349. }
  350. }
  351. return pop_seq;
  352. }
  353. static void janus_seq_list_free(seq_info_t **head) {
  354. if(!*head) return;
  355. seq_info_t *cur = *head;
  356. do {
  357. seq_info_t *next = cur->next;
  358. g_free(cur);
  359. cur = next;
  360. } while(cur != *head);
  361. *head = NULL;
  362. }
  363. static int janus_seq_in_range(guint16 seqn, guint16 start, guint16 len) {
  364. /* Supports wrapping sequence (easier with int range) */
  365. int n = seqn;
  366. int nh = (1<<16) + n;
  367. int s = start;
  368. int e = s + len;
  369. return (s <= n && n < e) || (s <= nh && nh < e);
  370. }
  371.  
  372.  
  373. /* Map of old plugin sessions that have been closed */
  374. static GHashTable *old_plugin_sessions;
  375. static janus_mutex old_plugin_sessions_mutex;
  376. gboolean janus_plugin_session_is_alive(janus_plugin_session *plugin_session) {
  377. /* Make sure this plugin session is still alive */
  378. janus_mutex_lock(&old_plugin_sessions_mutex);
  379. janus_plugin_session *result = g_hash_table_lookup(old_plugin_sessions, plugin_session);
  380. janus_mutex_unlock(&old_plugin_sessions_mutex);
  381. if(result != NULL) {
  382. JANUS_LOG(LOG_ERR, "Invalid plugin session (%p)\n", plugin_session);
  383. }
  384. return (result == NULL);
  385. }
  386.  
  387. /* Watchdog for removing old handles */
  388. static GHashTable *old_handles = NULL;
  389. static GMainContext *handles_watchdog_context = NULL;
  390. GMainLoop *handles_watchdog_loop = NULL;
  391. GThread *handles_watchdog = NULL;
  392. static janus_mutex old_handles_mutex;
  393.  
  394. static gboolean janus_ice_handles_cleanup(gpointer user_data) {
  395. janus_ice_handle *handle = (janus_ice_handle *) user_data;
  396.  
  397. JANUS_LOG(LOG_INFO, "Cleaning up handle %"SCNu64"...\n", handle->handle_id);
  398. janus_ice_free(handle);
  399.  
  400. return G_SOURCE_REMOVE;
  401. }
  402.  
  403. static gboolean janus_ice_handles_check(gpointer user_data) {
  404. GMainContext *watchdog_context = (GMainContext *) user_data;
  405. janus_mutex_lock(&old_handles_mutex);
  406. if(old_handles && g_hash_table_size(old_handles) > 0) {
  407. GHashTableIter iter;
  408. gpointer value;
  409. g_hash_table_iter_init(&iter, old_handles);
  410. while (g_hash_table_iter_next(&iter, NULL, &value)) {
  411. janus_ice_handle *handle = (janus_ice_handle *) value;
  412. if (!handle) {
  413. continue;
  414. }
  415. /* Schedule the ICE handle for deletion */
  416. g_hash_table_iter_remove(&iter);
  417. GSource *timeout_source = g_timeout_source_new_seconds(3);
  418. g_source_set_callback(timeout_source, janus_ice_handles_cleanup, handle, NULL);
  419. g_source_attach(timeout_source, watchdog_context);
  420. g_source_unref(timeout_source);
  421. }
  422. }
  423. janus_mutex_unlock(&old_handles_mutex);
  424.  
  425. if(janus_force_rtcpmux_blackhole_fd > 0) {
  426. /* Also read the blackhole socket (unneeded RTCP components keepalives) and dump the packets */
  427. char buffer[1500];
  428. struct sockaddr_storage addr;
  429. socklen_t len = sizeof(addr);
  430. ssize_t res = 0;
  431. do {
  432. /* Read and ignore */
  433. res = recvfrom(janus_force_rtcpmux_blackhole_fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&addr, &len);
  434. } while(res > -1);
  435. }
  436.  
  437. return G_SOURCE_CONTINUE;
  438. }
  439.  
  440. static gpointer janus_ice_handles_watchdog(gpointer user_data) {
  441. GMainLoop *loop = (GMainLoop *) user_data;
  442. GMainContext *watchdog_context = g_main_loop_get_context(loop);
  443. GSource *timeout_source;
  444.  
  445. timeout_source = g_timeout_source_new_seconds(1);
  446. g_source_set_callback(timeout_source, janus_ice_handles_check, watchdog_context, NULL);
  447. g_source_attach(timeout_source, watchdog_context);
  448. g_source_unref(timeout_source);
  449.  
  450. JANUS_LOG(LOG_INFO, "ICE handles watchdog started\n");
  451.  
  452. g_main_loop_run(loop);
  453.  
  454. return NULL;
  455. }
  456.  
  457.  
  458. void janus_ice_notify_media(janus_ice_handle *handle, gboolean video, gboolean up);
  459. void janus_ice_notify_media(janus_ice_handle *handle, gboolean video, gboolean up) {
  460. if(handle == NULL)
  461. return;
  462. /* Prepare JSON event to notify user/application */
  463. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Notifying that we %s receiving %s\n",
  464. handle->handle_id, up ? "are" : "are NOT", video ? "video" : "audio");
  465. janus_session *session = (janus_session *)handle->session;
  466. if(session == NULL)
  467. return;
  468. json_t *event = json_object();
  469. json_object_set_new(event, "janus", json_string("media"));
  470. json_object_set_new(event, "session_id", json_integer(session->session_id));
  471. json_object_set_new(event, "sender", json_integer(handle->handle_id));
  472. json_object_set_new(event, "type", json_string(video ? "video" : "audio"));
  473. json_object_set_new(event, "receiving", json_string(up ? "true" : "false"));
  474. /* Send the event */
  475. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...\n", handle->handle_id);
  476. janus_session_notify_event(session->session_id, event);
  477. }
  478.  
  479. void janus_ice_notify_hangup(janus_ice_handle *handle, const char *reason) {
  480. if(handle == NULL)
  481. return;
  482. /* Prepare JSON event to notify user/application */
  483. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Notifying WebRTC hangup\n", handle->handle_id);
  484. janus_session *session = (janus_session *)handle->session;
  485. if(session == NULL)
  486. return;
  487. json_t *event = json_object();
  488. json_object_set_new(event, "janus", json_string("hangup"));
  489. json_object_set_new(event, "session_id", json_integer(session->session_id));
  490. json_object_set_new(event, "sender", json_integer(handle->handle_id));
  491. if(reason != NULL)
  492. json_object_set_new(event, "reason", json_string(reason));
  493. /* Send the event */
  494. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...\n", handle->handle_id);
  495. janus_session_notify_event(session->session_id, event);
  496. }
  497.  
  498.  
  499. /* Trickle helpers */
  500. janus_ice_trickle *janus_ice_trickle_new(janus_ice_handle *handle, const char *transaction, json_t *candidate) {
  501. if(transaction == NULL || candidate == NULL)
  502. return NULL;
  503. janus_ice_trickle *trickle = g_malloc0(sizeof(janus_ice_trickle));
  504. trickle->handle = handle;
  505. trickle->received = janus_get_monotonic_time();
  506. trickle->transaction = g_strdup(transaction);
  507. trickle->candidate = json_deep_copy(candidate);
  508. return trickle;
  509. }
  510.  
  511. gint janus_ice_trickle_parse(janus_ice_handle *handle, json_t *candidate, const char **error) {
  512. const char *ignore_error = NULL;
  513. if (error == NULL) {
  514. error = &ignore_error;
  515. }
  516. if(handle == NULL) {
  517. *error = "Invalid handle";
  518. return JANUS_ERROR_HANDLE_NOT_FOUND;
  519. }
  520. /* Parse trickle candidate */
  521. if(!json_is_object(candidate) || json_object_get(candidate, "completed") != NULL) {
  522. JANUS_LOG(LOG_VERB, "No more remote candidates for handle %"SCNu64"!\n", handle->handle_id);
  523. janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES);
  524. } else {
  525. /* Handle remote candidate */
  526. json_t *mid = json_object_get(candidate, "sdpMid");
  527. if(!mid) {
  528. *error = "Trickle error: missing mandatory element (sdpMid)";
  529. return JANUS_ERROR_MISSING_MANDATORY_ELEMENT;
  530. }
  531. if(!json_is_string(mid)) {
  532. *error = "Trickle error: invalid element type (sdpMid should be a string)";
  533. return JANUS_ERROR_INVALID_ELEMENT_TYPE;
  534. }
  535. json_t *mline = json_object_get(candidate, "sdpMLineIndex");
  536. if(!mline) {
  537. *error = "Trickle error: missing mandatory element (sdpMLineIndex)";
  538. return JANUS_ERROR_MISSING_MANDATORY_ELEMENT;
  539. }
  540. if(!json_is_integer(mline) || json_integer_value(mline) < 0) {
  541. *error = "Trickle error: invalid element type (sdpMLineIndex should be an integer)";
  542. return JANUS_ERROR_INVALID_ELEMENT_TYPE;
  543. }
  544. json_t *rc = json_object_get(candidate, "candidate");
  545. if(!rc) {
  546. *error = "Trickle error: missing mandatory element (candidate)";
  547. return JANUS_ERROR_MISSING_MANDATORY_ELEMENT;
  548. }
  549. if(!json_is_string(rc)) {
  550. *error = "Trickle error: invalid element type (candidate should be a string)";
  551. return JANUS_ERROR_INVALID_ELEMENT_TYPE;
  552. }
  553. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Trickle candidate (%s): %s\n", handle->handle_id, json_string_value(mid), json_string_value(rc));
  554. /* Parse it */
  555. int sdpMLineIndex = json_integer_value(mline);
  556. int video = 0, data = 0;
  557. /* FIXME badly, we should have an array of m-lines in the handle object */
  558. switch(sdpMLineIndex) {
  559. case 0:
  560. if(handle->audio_stream == NULL) {
  561. video = handle->video_stream ? 1 : 0;
  562. data = !video;
  563. }
  564. break;
  565. case 1:
  566. if(handle->audio_stream == NULL) {
  567. data = 1;
  568. } else {
  569. video = handle->video_stream ? 1 : 0;
  570. data = !video;
  571. }
  572. break;
  573. case 2:
  574. data = 1;
  575. break;
  576. default:
  577. /* FIXME We don't support more than 3 m-lines right now */
  578. *error = "Trickle error: invalid element type (sdpMLineIndex not [0,2])";
  579. return JANUS_ERROR_INVALID_ELEMENT_TYPE;
  580. }
  581. #ifndef HAVE_SCTP
  582. data = 0;
  583. #endif
  584. if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE)
  585. && sdpMLineIndex != 0) {
  586. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Got a %s candidate but we're bundling, ignoring...\n", handle->handle_id, json_string_value(mid));
  587. } else {
  588. janus_ice_stream *stream = video ? handle->video_stream : (data ? handle->data_stream : handle->audio_stream);
  589. if(stream == NULL) {
  590. *error = "Trickle error: invalid element type (no such stream)";
  591. return JANUS_ERROR_TRICKE_INVALID_STREAM;
  592. }
  593. int res = janus_sdp_parse_candidate(stream, json_string_value(rc), 1);
  594. if(res != 0) {
  595. JANUS_LOG(LOG_ERR, "[%"SCNu64"] Failed to parse candidate... (%d)\n", handle->handle_id, res);
  596. /* FIXME Should we return an error? */
  597. }
  598. }
  599. }
  600. return 0;
  601. }
  602.  
  603. void janus_ice_trickle_destroy(janus_ice_trickle *trickle) {
  604. if(trickle == NULL)
  605. return;
  606. trickle->handle = NULL;
  607. if(trickle->transaction)
  608. g_free(trickle->transaction);
  609. trickle->transaction = NULL;
  610. if(trickle->candidate)
  611. json_decref(trickle->candidate);
  612. trickle->candidate = NULL;
  613. g_free(trickle);
  614. }
  615.  
  616.  
  617. /* libnice initialization */
  618. void janus_ice_init(gboolean ice_lite, gboolean ice_tcp, gboolean ipv6, uint16_t rtp_min_port, uint16_t rtp_max_port) {
  619. janus_ice_lite_enabled = ice_lite;
  620. janus_ice_tcp_enabled = ice_tcp;
  621. janus_ipv6_enabled = ipv6;
  622. JANUS_LOG(LOG_INFO, "Initializing ICE stuff (%s mode, ICE-TCP candidates %s, IPv6 support %s)\n",
  623. janus_ice_lite_enabled ? "Lite" : "Full",
  624. janus_ice_tcp_enabled ? "enabled" : "disabled",
  625. janus_ipv6_enabled ? "enabled" : "disabled");
  626. if(janus_ice_tcp_enabled) {
  627. #ifndef HAVE_LIBNICE_TCP
  628. JANUS_LOG(LOG_WARN, "libnice version < 0.1.8, disabling ICE-TCP support\n");
  629. janus_ice_tcp_enabled = FALSE;
  630. #else
  631. if(!janus_ice_lite_enabled) {
  632. JANUS_LOG(LOG_WARN, "ICE-TCP only works in libnice if you enable ICE Lite too: disabling ICE-TCP support\n");
  633. janus_ice_tcp_enabled = FALSE;
  634. }
  635. #endif
  636. }
  637. /* libnice debugging is disabled unless explicitly stated */
  638. nice_debug_disable(TRUE);
  639.  
  640. /*! \note The RTP/RTCP port range configuration may be just a placeholder: for
  641. * instance, libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails
  642. * when linking with an undefined reference to \c nice_agent_set_port_range
  643. * so this is checked by the install.sh script in advance. */
  644. rtp_range_min = rtp_min_port;
  645. rtp_range_max = rtp_max_port;
  646. if(rtp_range_max < rtp_range_min) {
  647. JANUS_LOG(LOG_WARN, "Invalid ICE port range: %"SCNu16" > %"SCNu16"\n", rtp_range_min, rtp_range_max);
  648. } else if(rtp_range_min > 0 || rtp_range_max > 0) {
  649. #ifndef HAVE_PORTRANGE
  650. JANUS_LOG(LOG_WARN, "nice_agent_set_port_range unavailable, port range disabled\n");
  651. #else
  652. JANUS_LOG(LOG_INFO, "ICE port range: %"SCNu16"-%"SCNu16"\n", rtp_range_min, rtp_range_max);
  653. #endif
  654. }
  655.  
  656. /* We keep track of old plugin sessions to avoid problems */
  657. old_plugin_sessions = g_hash_table_new(NULL, NULL);
  658. janus_mutex_init(&old_plugin_sessions_mutex);
  659.  
  660. /* Start the handles watchdog */
  661. janus_mutex_init(&old_handles_mutex);
  662. old_handles = g_hash_table_new(NULL, NULL);
  663. handles_watchdog_context = g_main_context_new();
  664. handles_watchdog_loop = g_main_loop_new(handles_watchdog_context, FALSE);
  665. GError *error = NULL;
  666. handles_watchdog = g_thread_try_new("handles watchdog", &janus_ice_handles_watchdog, handles_watchdog_loop, &error);
  667. if(error != NULL) {
  668. JANUS_LOG(LOG_FATAL, "Got error %d (%s) trying to start handles watchdog...\n", error->code, error->message ? error->message : "??");
  669. exit(1);
  670. }
  671.  
  672. #ifdef HAVE_LIBCURL
  673. /* Initialize the TURN REST API client stack, whether we're going to use it or not */
  674. janus_turnrest_init();
  675. #endif
  676.  
  677. }
  678.  
  679. void janus_ice_deinit(void) {
  680. JANUS_LOG(LOG_INFO, "Ending ICE handles watchdog mainloop...\n");
  681. g_main_loop_quit(handles_watchdog_loop);
  682. g_thread_join(handles_watchdog);
  683. handles_watchdog = NULL;
  684. g_main_loop_unref(handles_watchdog_loop);
  685. g_main_context_unref(handles_watchdog_context);
  686. janus_mutex_lock(&old_handles_mutex);
  687. if(old_handles != NULL)
  688. g_hash_table_destroy(old_handles);
  689. old_handles = NULL;
  690. janus_mutex_unlock(&old_handles_mutex);
  691. #ifdef HAVE_LIBCURL
  692. janus_turnrest_deinit();
  693. #endif
  694. }
  695.  
  696. int janus_ice_set_stun_server(gchar *stun_server, uint16_t stun_port) {
  697. if(stun_server == NULL)
  698. return 0; /* No initialization needed */
  699. if(stun_port == 0)
  700. stun_port = 3478;
  701. JANUS_LOG(LOG_INFO, "STUN server to use: %s:%u\n", stun_server, stun_port);
  702. /* Resolve address to get an IP */
  703. struct addrinfo *res = NULL;
  704. if(getaddrinfo(stun_server, NULL, NULL, &res) != 0) {
  705. JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", stun_server);
  706. if(res)
  707. freeaddrinfo(res);
  708. return -1;
  709. }
  710. janus_stun_server = janus_address_to_ip(res->ai_addr);
  711. freeaddrinfo(res);
  712. if(janus_stun_server == NULL) {
  713. JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", stun_server);
  714. return -1;
  715. }
  716. janus_stun_port = stun_port;
  717. JANUS_LOG(LOG_VERB, " >> %s:%u\n", janus_stun_server, janus_stun_port);
  718. /* Test the STUN server */
  719. StunAgent stun;
  720. stun_agent_init (&stun, STUN_ALL_KNOWN_ATTRIBUTES, STUN_COMPATIBILITY_RFC5389, 0);
  721. StunMessage msg;
  722. uint8_t buf[1500];
  723. size_t len = stun_usage_bind_create(&stun, &msg, buf, 1500);
  724. JANUS_LOG(LOG_INFO, "Testing STUN server: message is of %zu bytes\n", len);
  725. int fd = socket(AF_INET, SOCK_DGRAM, 0);
  726. struct sockaddr_in address, remote;
  727. address.sin_family = AF_INET;
  728. address.sin_port = 0;
  729. address.sin_addr.s_addr = INADDR_ANY;
  730. remote.sin_family = AF_INET;
  731. remote.sin_port = htons(janus_stun_port);
  732. remote.sin_addr.s_addr = inet_addr(janus_stun_server);
  733. if(bind(fd, (struct sockaddr *)(&address), sizeof(struct sockaddr)) < 0) {
  734. JANUS_LOG(LOG_FATAL, "Bind failed for STUN BINDING test\n");
  735. return -1;
  736. }
  737. int bytes = sendto(fd, buf, len, 0, (struct sockaddr*)&remote, sizeof(remote));
  738. if(bytes < 0) {
  739. JANUS_LOG(LOG_FATAL, "Error sending STUN BINDING test\n");
  740. return -1;
  741. }
  742. JANUS_LOG(LOG_VERB, " >> Sent %d bytes %s:%u, waiting for reply...\n", bytes, janus_stun_server, janus_stun_port);
  743. struct timeval timeout;
  744. fd_set readfds;
  745. FD_ZERO(&readfds);
  746. FD_SET(fd, &readfds);
  747. timeout.tv_sec = 5; /* FIXME Don't wait forever */
  748. timeout.tv_usec = 0;
  749. select(fd+1, &readfds, NULL, NULL, &timeout);
  750. if(!FD_ISSET(fd, &readfds)) {
  751. JANUS_LOG(LOG_FATAL, "No response to our STUN BINDING test\n");
  752. return -1;
  753. }
  754. socklen_t addrlen = sizeof(remote);
  755. bytes = recvfrom(fd, buf, 1500, 0, (struct sockaddr*)&remote, &addrlen);
  756. JANUS_LOG(LOG_VERB, " >> Got %d bytes...\n", bytes);
  757. if(stun_agent_validate (&stun, &msg, buf, bytes, NULL, NULL) != STUN_VALIDATION_SUCCESS) {
  758. JANUS_LOG(LOG_FATAL, "Failed to validate STUN BINDING response\n");
  759. return -1;
  760. }
  761. StunClass class = stun_message_get_class(&msg);
  762. StunMethod method = stun_message_get_method(&msg);
  763. if(class != STUN_RESPONSE || method != STUN_BINDING) {
  764. JANUS_LOG(LOG_FATAL, "Unexpected STUN response: %d/%d\n", class, method);
  765. return -1;
  766. }
  767. StunMessageReturn ret = stun_message_find_xor_addr(&msg, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, (struct sockaddr_storage *)&address, &addrlen);
  768. JANUS_LOG(LOG_VERB, " >> XOR-MAPPED-ADDRESS: %d\n", ret);
  769. if(ret == STUN_MESSAGE_RETURN_SUCCESS) {
  770. char *public_ip = janus_address_to_ip((struct sockaddr *)&address);
  771. JANUS_LOG(LOG_INFO, " >> Our public address is %s\n", public_ip);
  772. janus_set_public_ip(public_ip);
  773. g_free(public_ip);
  774. return 0;
  775. }
  776. ret = stun_message_find_addr(&msg, STUN_ATTRIBUTE_MAPPED_ADDRESS, (struct sockaddr_storage *)&address, &addrlen);
  777. JANUS_LOG(LOG_VERB, " >> MAPPED-ADDRESS: %d\n", ret);
  778. if(ret == STUN_MESSAGE_RETURN_SUCCESS) {
  779. char *public_ip = janus_address_to_ip((struct sockaddr *)&address);
  780. JANUS_LOG(LOG_INFO, " >> Our public address is %s\n", public_ip);
  781. janus_set_public_ip(public_ip);
  782. g_free(public_ip);
  783. return 0;
  784. }
  785. return -1;
  786. }
  787.  
  788. int janus_ice_set_turn_server(gchar *turn_server, uint16_t turn_port, gchar *turn_type, gchar *turn_user, gchar *turn_pwd) {
  789. if(turn_server == NULL)
  790. return 0; /* No initialization needed */
  791. if(turn_type == NULL)
  792. turn_type = (char *)"udp";
  793. if(turn_port == 0)
  794. turn_port = 3478;
  795. JANUS_LOG(LOG_INFO, "TURN server to use: %s:%u (%s)\n", turn_server, turn_port, turn_type);
  796. if(!strcasecmp(turn_type, "udp")) {
  797. janus_turn_type = NICE_RELAY_TYPE_TURN_UDP;
  798. } else if(!strcasecmp(turn_type, "tcp")) {
  799. janus_turn_type = NICE_RELAY_TYPE_TURN_TCP;
  800. } else if(!strcasecmp(turn_type, "tls")) {
  801. janus_turn_type = NICE_RELAY_TYPE_TURN_TLS;
  802. } else {
  803. JANUS_LOG(LOG_ERR, "Unsupported relay type '%s'...\n", turn_type);
  804. return -1;
  805. }
  806. /* Resolve address to get an IP */
  807. struct addrinfo *res = NULL;
  808. if(getaddrinfo(turn_server, NULL, NULL, &res) != 0) {
  809. JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", turn_server);
  810. if(res)
  811. freeaddrinfo(res);
  812. return -1;
  813. }
  814. if(janus_turn_server != NULL)
  815. g_free(janus_turn_server);
  816. janus_turn_server = janus_address_to_ip(res->ai_addr);
  817. freeaddrinfo(res);
  818. if(janus_turn_server == NULL) {
  819. JANUS_LOG(LOG_ERR, "Could not resolve %s...\n", turn_server);
  820. return -1;
  821. }
  822. janus_turn_port = turn_port;
  823. JANUS_LOG(LOG_VERB, " >> %s:%u\n", janus_turn_server, janus_turn_port);
  824. if(janus_turn_user != NULL)
  825. g_free(janus_turn_user);
  826. janus_turn_user = NULL;
  827. if(turn_user)
  828. janus_turn_user = g_strdup(turn_user);
  829. if(janus_turn_pwd != NULL)
  830. g_free(janus_turn_pwd);
  831. janus_turn_pwd = NULL;
  832. if(turn_pwd)
  833. janus_turn_pwd = g_strdup(turn_pwd);
  834. return 0;
  835. }
  836.  
  837. int janus_ice_set_turn_rest_api(gchar *api_server, gchar *api_key, gchar *api_method) {
  838. #ifndef HAVE_LIBCURL
  839. JANUS_LOG(LOG_ERR, "Janus has been nuilt with no libcurl support, TURN REST API unavailable\n");
  840. return -1;
  841. #else
  842. if(api_server != NULL &&
  843. (strstr(api_server, "http://") != api_server && strstr(api_server, "https://") != api_server)) {
  844. JANUS_LOG(LOG_ERR, "Invalid TURN REST API backend: not an HTTP address\n");
  845. return -1;
  846. }
  847. janus_turnrest_set_backend(api_server, api_key, api_method);
  848. JANUS_LOG(LOG_INFO, "TURN REST API backend: %s\n", api_server ? api_server : "(disabled)");
  849. #endif
  850. return 0;
  851. }
  852.  
  853.  
  854. /* ICE stuff */
  855. static const gchar *janus_ice_state_name[] =
  856. {
  857. "disconnected",
  858. "gathering",
  859. "connecting",
  860. "connected",
  861. "ready",
  862. "failed"
  863. };
  864. const gchar *janus_get_ice_state_name(gint state) {
  865. if(state < 0 || state > 5)
  866. return NULL;
  867. return janus_ice_state_name[state];
  868. }
  869.  
  870. /* Stats */
  871. void janus_ice_stats_queue_free(gpointer data);
  872. void janus_ice_stats_queue_free(gpointer data) {
  873. janus_ice_stats_item *s = (janus_ice_stats_item *)data;
  874. g_free(s);
  875. }
  876.  
  877. void janus_ice_stats_reset(janus_ice_stats *stats) {
  878. if(stats == NULL)
  879. return;
  880. stats->audio_packets = 0;
  881. stats->audio_bytes = 0;
  882. if(stats->audio_bytes_lastsec)
  883. g_list_free_full(stats->audio_bytes_lastsec, &janus_ice_stats_queue_free);
  884. stats->audio_bytes_lastsec = NULL;
  885. stats->audio_notified_lastsec = FALSE;
  886. stats->audio_nacks = 0;
  887. stats->video_packets = 0;
  888. stats->video_bytes = 0;
  889. if(stats->video_bytes_lastsec)
  890. g_list_free_full(stats->video_bytes_lastsec, &janus_ice_stats_queue_free);
  891. stats->video_bytes_lastsec = NULL;
  892. stats->video_notified_lastsec = FALSE;
  893. stats->video_nacks = 0;
  894. stats->data_packets = 0;
  895. stats->data_bytes = 0;
  896. }
  897.  
  898.  
  899. /* ICE Handles */
  900. janus_ice_handle *janus_ice_handle_create(void *gateway_session) {
  901. if(gateway_session == NULL)
  902. return NULL;
  903. janus_session *session = (janus_session *)gateway_session;
  904. guint64 handle_id = 0;
  905. while(handle_id == 0) {
  906. handle_id = g_random_int();
  907. if(janus_ice_handle_find(gateway_session, handle_id) != NULL) {
  908. /* Handle ID already taken, try another one */
  909. handle_id = 0;
  910. }
  911. }
  912. JANUS_LOG(LOG_INFO, "Creating new handle in session %"SCNu64": %"SCNu64"\n", session->session_id, handle_id);
  913. janus_ice_handle *handle = (janus_ice_handle *)g_malloc0(sizeof(janus_ice_handle));
  914. if(handle == NULL) {
  915. JANUS_LOG(LOG_FATAL, "Memory error!\n");
  916. return NULL;
  917. }
  918. handle->session = gateway_session;
  919. handle->created = janus_get_monotonic_time();
  920. handle->handle_id = handle_id;
  921. handle->app = NULL;
  922. handle->app_handle = NULL;
  923. janus_mutex_init(&handle->mutex);
  924.  
  925. /* Set up other stuff. */
  926. janus_mutex_lock(&session->mutex);
  927. if(session->ice_handles == NULL)
  928. session->ice_handles = g_hash_table_new(NULL, NULL);
  929. g_hash_table_insert(session->ice_handles, GUINT_TO_POINTER(handle_id), handle);
  930. janus_mutex_unlock(&session->mutex);
  931.  
  932. return handle;
  933. }
  934.  
  935. janus_ice_handle *janus_ice_handle_find(void *gateway_session, guint64 handle_id) {
  936. if(gateway_session == NULL)
  937. return NULL;
  938. janus_session *session = (janus_session *)gateway_session;
  939. janus_mutex_lock(&session->mutex);
  940. janus_ice_handle *handle = session->ice_handles ? g_hash_table_lookup(session->ice_handles, GUINT_TO_POINTER(handle_id)) : NULL;
  941. janus_mutex_unlock(&session->mutex);
  942. return handle;
  943. }
  944.  
  945. gint janus_ice_handle_attach_plugin(void *gateway_session, guint64 handle_id, janus_plugin *plugin) {
  946. if(gateway_session == NULL)
  947. return JANUS_ERROR_SESSION_NOT_FOUND;
  948. if(plugin == NULL)
  949. return JANUS_ERROR_PLUGIN_NOT_FOUND;
  950. janus_session *session = (janus_session *)gateway_session;
  951. janus_ice_handle *handle = janus_ice_handle_find(session, handle_id);
  952. if(handle == NULL)
  953. return JANUS_ERROR_HANDLE_NOT_FOUND;
  954. janus_mutex_lock(&session->mutex);
  955. if(handle->app != NULL) {
  956. /* This handle is already attached to a plugin */
  957. janus_mutex_unlock(&session->mutex);
  958. return JANUS_ERROR_PLUGIN_ATTACH;
  959. }
  960. int error = 0;
  961. janus_plugin_session *session_handle = g_malloc0(sizeof(janus_plugin_session));
  962. if(session_handle == NULL) {
  963. JANUS_LOG(LOG_FATAL, "Memory error!\n");
  964. janus_mutex_unlock(&session->mutex);
  965. return JANUS_ERROR_UNKNOWN; /* FIXME Do we need something like "Internal Server Error"? */
  966. }
  967. session_handle->gateway_handle = handle;
  968. session_handle->plugin_handle = NULL;
  969. session_handle->stopped = 0;
  970. plugin->create_session(session_handle, &error);
  971. if(error) {
  972. /* TODO Make error struct to pass verbose information */
  973. janus_mutex_unlock(&session->mutex);
  974. return error;
  975. }
  976. handle->app = plugin;
  977. handle->app_handle = session_handle;
  978. /* Make sure this plugin session is not in the old sessions list */
  979. janus_mutex_lock(&old_plugin_sessions_mutex);
  980. g_hash_table_remove(old_plugin_sessions, session_handle);
  981. janus_mutex_unlock(&old_plugin_sessions_mutex);
  982. janus_mutex_unlock(&session->mutex);
  983. return 0;
  984. }
  985.  
  986. gint janus_ice_handle_destroy(void *gateway_session, guint64 handle_id) {
  987. if(gateway_session == NULL)
  988. return JANUS_ERROR_SESSION_NOT_FOUND;
  989. janus_session *session = (janus_session *)gateway_session;
  990. janus_ice_handle *handle = janus_ice_handle_find(session, handle_id);
  991. if(handle == NULL)
  992. return JANUS_ERROR_HANDLE_NOT_FOUND;
  993. janus_mutex_lock(&session->mutex);
  994. janus_plugin *plugin_t = (janus_plugin *)handle->app;
  995. if(plugin_t == NULL) {
  996. /* There was no plugin attached, probably something went wrong there */
  997. janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
  998. janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP);
  999. if(handle->iceloop)
  1000. g_main_loop_quit(handle->iceloop);
  1001. janus_mutex_unlock(&session->mutex);
  1002. return 0;
  1003. }
  1004. JANUS_LOG(LOG_INFO, "Detaching handle from %s\n", plugin_t->get_name());
  1005. /* TODO Actually detach handle... */
  1006. int error = 0;
  1007. janus_mutex_lock(&old_plugin_sessions_mutex);
  1008. /* This is to tell the plugin to stop using this session: we'll get rid of it later */
  1009. handle->app_handle->stopped = 1;
  1010. /* And this is to put the plugin session in the old sessions list, to avoid it being used */
  1011. g_hash_table_insert(old_plugin_sessions, handle->app_handle, handle->app_handle);
  1012. janus_mutex_unlock(&old_plugin_sessions_mutex);
  1013. /* Notify the plugin that the session's over */
  1014. plugin_t->destroy_session(handle->app_handle, &error);
  1015. /* Get rid of the handle now */
  1016. janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
  1017. janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP);
  1018. if(handle->iceloop)
  1019. g_main_loop_quit(handle->iceloop);
  1020.  
  1021. /* Prepare JSON event to notify user/application */
  1022. json_t *event = json_object();
  1023. json_object_set_new(event, "janus", json_string("detached"));
  1024. json_object_set_new(event, "session_id", json_integer(session->session_id));
  1025. json_object_set_new(event, "sender", json_integer(handle_id));
  1026. /* Send the event */
  1027. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...\n", handle->handle_id);
  1028. janus_session_notify_event(session->session_id, event);
  1029. janus_mutex_unlock(&session->mutex);
  1030. /* We only actually destroy the handle later */
  1031. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Handle detached (error=%d), scheduling destruction\n", handle_id, error);
  1032. janus_mutex_lock(&old_handles_mutex);
  1033. g_hash_table_insert(old_handles, GUINT_TO_POINTER(handle_id), handle);
  1034. janus_mutex_unlock(&old_handles_mutex);
  1035. return error;
  1036. }
  1037.  
  1038. void janus_ice_free(janus_ice_handle *handle) {
  1039. if(handle == NULL)
  1040. return;
  1041. janus_mutex_lock(&handle->mutex);
  1042. handle->session = NULL;
  1043. handle->app = NULL;
  1044. if(handle->app_handle != NULL) {
  1045. janus_mutex_lock(&old_plugin_sessions_mutex);
  1046. handle->app_handle->stopped = 1;
  1047. g_hash_table_insert(old_plugin_sessions, handle->app_handle, handle->app_handle);
  1048. handle->app_handle->gateway_handle = NULL;
  1049. handle->app_handle->plugin_handle = NULL;
  1050. g_free(handle->app_handle);
  1051. handle->app_handle = NULL;
  1052. janus_mutex_unlock(&old_plugin_sessions_mutex);
  1053. }
  1054. janus_mutex_unlock(&handle->mutex);
  1055. janus_ice_webrtc_free(handle);
  1056. JANUS_LOG(LOG_INFO, "[%"SCNu64"] Handle and related resources freed\n", handle->handle_id);
  1057. g_free(handle);
  1058. handle = NULL;
  1059. }
  1060.  
  1061. void janus_ice_webrtc_hangup(janus_ice_handle *handle) {
  1062. if(handle == NULL)
  1063. return;
  1064. if(handle->queued_packets != NULL)
  1065. g_async_queue_push(handle->queued_packets, &janus_ice_dtls_alert);
  1066. if(handle->send_thread == NULL) {
  1067. /* Get rid of the loop */
  1068. if(handle->iceloop) {
  1069. gint64 waited = 0;
  1070. while(handle->iceloop && !g_main_loop_is_running(handle->iceloop)) {
  1071. JANUS_LOG(LOG_VERB, "[%"SCNu64"] ICE loop exists but is not running, waiting for it to run\n", handle->handle_id);
  1072. g_usleep (100000);
  1073. waited += 100000;
  1074. if(waited >= G_USEC_PER_SEC) {
  1075. JANUS_LOG(LOG_VERB, "[%"SCNu64"] -- Waited a second, that's enough!\n", handle->handle_id);
  1076. break;
  1077. }
  1078. }
  1079. if(handle->iceloop && g_main_loop_is_running(handle->iceloop)) {
  1080. 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");
  1081. g_main_loop_quit(handle->iceloop);
  1082. g_main_context_wakeup(handle->icectx);
  1083. }
  1084. }
  1085. }
  1086. handle->icethread = NULL;
  1087. }
  1088.  
  1089. void janus_ice_webrtc_free(janus_ice_handle *handle) {
  1090. if(handle == NULL)
  1091. return;
  1092. janus_mutex_lock(&handle->mutex);
  1093. if(handle->iceloop != NULL) {
  1094. g_main_loop_unref (handle->iceloop);
  1095. handle->iceloop = NULL;
  1096. }
  1097. if(handle->icectx != NULL) {
  1098. g_main_context_unref (handle->icectx);
  1099. handle->icectx = NULL;
  1100. }
  1101. handle->icethread = NULL;
  1102. if(handle->streams != NULL) {
  1103. janus_ice_stream_free(handle->streams, handle->audio_stream);
  1104. handle->audio_stream = NULL;
  1105. janus_ice_stream_free(handle->streams, handle->video_stream);
  1106. handle->video_stream = NULL;
  1107. janus_ice_stream_free(handle->streams, handle->data_stream);
  1108. handle->data_stream = NULL;
  1109. g_hash_table_destroy(handle->streams);
  1110. handle->streams = NULL;
  1111. }
  1112. if(handle->agent != NULL) {
  1113. if(G_IS_OBJECT(handle->agent))
  1114. g_object_unref(handle->agent);
  1115. handle->agent = NULL;
  1116. }
  1117. handle->agent_created = 0;
  1118. if(handle->pending_trickles) {
  1119. while(handle->pending_trickles) {
  1120. GList *temp = g_list_first(handle->pending_trickles);
  1121. handle->pending_trickles = g_list_remove_link(handle->pending_trickles, temp);
  1122. janus_ice_trickle *trickle = (janus_ice_trickle *)temp->data;
  1123. g_list_free(temp);
  1124. janus_ice_trickle_destroy(trickle);
  1125. }
  1126. }
  1127. handle->pending_trickles = NULL;
  1128. g_free(handle->rtp_profile);
  1129. handle->rtp_profile = NULL;
  1130. g_free(handle->local_sdp);
  1131. handle->local_sdp = NULL;
  1132. g_free(handle->remote_sdp);
  1133. handle->remote_sdp = NULL;
  1134. if(handle->queued_packets != NULL) {
  1135. janus_ice_queued_packet *pkt = NULL;
  1136. while(g_async_queue_length(handle->queued_packets) > 0) {
  1137. pkt = g_async_queue_try_pop(handle->queued_packets);
  1138. if(pkt != NULL && pkt != &janus_ice_dtls_alert) {
  1139. g_free(pkt->data);
  1140. pkt->data = NULL;
  1141. g_free(pkt);
  1142. pkt = NULL;
  1143. }
  1144. }
  1145. g_async_queue_unref(handle->queued_packets);
  1146. handle->queued_packets = NULL;
  1147. }
  1148. if(handle->audio_mid != NULL) {
  1149. g_free(handle->audio_mid);
  1150. handle->audio_mid = NULL;
  1151. }
  1152. if(handle->video_mid != NULL) {
  1153. g_free(handle->video_mid);
  1154. handle->video_mid = NULL;
  1155. }
  1156. if(handle->data_mid != NULL) {
  1157. g_free(handle->data_mid);
  1158. handle->data_mid = NULL;
  1159. }
  1160. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY);
  1161. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING);
  1162. g_atomic_int_set(&handle->send_thread_created, 0);
  1163. janus_mutex_unlock(&handle->mutex);
  1164. JANUS_LOG(LOG_INFO, "[%"SCNu64"] WebRTC resources freed\n", handle->handle_id);
  1165. }
  1166.  
  1167. void janus_ice_stream_free(GHashTable *streams, janus_ice_stream *stream) {
  1168. if(stream == NULL)
  1169. return;
  1170. if(streams != NULL)
  1171. g_hash_table_remove(streams, GUINT_TO_POINTER(stream->stream_id));
  1172. if(stream->components != NULL) {
  1173. janus_ice_component_free(stream->components, stream->rtp_component);
  1174. stream->rtp_component = NULL;
  1175. janus_ice_component_free(stream->components, stream->rtcp_component);
  1176. stream->rtcp_component = NULL;
  1177. g_hash_table_destroy(stream->components);
  1178. }
  1179. stream->handle = NULL;
  1180. if(stream->remote_hashing != NULL) {
  1181. g_free(stream->remote_hashing);
  1182. stream->remote_hashing = NULL;
  1183. }
  1184. if(stream->remote_fingerprint != NULL) {
  1185. g_free(stream->remote_fingerprint);
  1186. stream->remote_fingerprint = NULL;
  1187. }
  1188. if(stream->ruser != NULL) {
  1189. g_free(stream->ruser);
  1190. stream->ruser = NULL;
  1191. }
  1192. if(stream->rpass != NULL) {
  1193. g_free(stream->rpass);
  1194. stream->rpass = NULL;
  1195. }
  1196. g_list_free(stream->audio_payload_types);
  1197. stream->audio_payload_types = NULL;
  1198. g_list_free(stream->video_payload_types);
  1199. stream->video_payload_types = NULL;
  1200. g_free(stream->audio_rtcp_ctx);
  1201. stream->audio_rtcp_ctx = NULL;
  1202. g_free(stream->video_rtcp_ctx);
  1203. stream->video_rtcp_ctx = NULL;
  1204. stream->audio_last_ts = 0;
  1205. stream->video_last_ts = 0;
  1206. g_free(stream);
  1207. stream = NULL;
  1208. }
  1209.  
  1210. void janus_ice_component_free(GHashTable *components, janus_ice_component *component) {
  1211. if(component == NULL)
  1212. return;
  1213. janus_ice_stream *stream = component->stream;
  1214. if(stream == NULL)
  1215. return;
  1216. janus_ice_handle *handle = stream->handle;
  1217. if(handle == NULL)
  1218. return;
  1219. //~ janus_mutex_lock(&handle->mutex);
  1220. if(components != NULL)
  1221. g_hash_table_remove(components, GUINT_TO_POINTER(component->component_id));
  1222. component->stream = NULL;
  1223. if(component->source != NULL) {
  1224. g_source_destroy(component->source);
  1225. g_source_unref(component->source);
  1226. component->source = NULL;
  1227. }
  1228. if(component->dtls != NULL) {
  1229. janus_dtls_srtp_destroy(component->dtls);
  1230. component->dtls = NULL;
  1231. }
  1232. if(component->retransmit_buffer != NULL) {
  1233. janus_rtp_packet *p = NULL;
  1234. GList *first = g_list_first(component->retransmit_buffer);
  1235. while(first != NULL) {
  1236. p = (janus_rtp_packet *)first->data;
  1237. first->data = NULL;
  1238. component->retransmit_buffer = g_list_delete_link(component->retransmit_buffer, first);
  1239. g_free(p->data);
  1240. p->data = NULL;
  1241. g_free(p);
  1242. first = g_list_first(component->retransmit_buffer);
  1243. }
  1244. }
  1245. if(component->candidates != NULL) {
  1246. GSList *i = NULL, *candidates = component->candidates;
  1247. for (i = candidates; i; i = i->next) {
  1248. NiceCandidate *c = (NiceCandidate *) i->data;
  1249. if(c != NULL) {
  1250. nice_candidate_free(c);
  1251. c = NULL;
  1252. }
  1253. }
  1254. g_slist_free(candidates);
  1255. candidates = NULL;
  1256. }
  1257. component->candidates = NULL;
  1258. if(component->local_candidates != NULL) {
  1259. GSList *i = NULL, *candidates = component->local_candidates;
  1260. for (i = candidates; i; i = i->next) {
  1261. gchar *c = (gchar *) i->data;
  1262. if(c != NULL) {
  1263. g_free(c);
  1264. c = NULL;
  1265. }
  1266. }
  1267. g_slist_free(candidates);
  1268. candidates = NULL;
  1269. }
  1270. component->local_candidates = NULL;
  1271. if(component->remote_candidates != NULL) {
  1272. GSList *i = NULL, *candidates = component->remote_candidates;
  1273. for (i = candidates; i; i = i->next) {
  1274. gchar *c = (gchar *) i->data;
  1275. if(c != NULL) {
  1276. g_free(c);
  1277. c = NULL;
  1278. }
  1279. }
  1280. g_slist_free(candidates);
  1281. candidates = NULL;
  1282. }
  1283. component->remote_candidates = NULL;
  1284. if(component->selected_pair != NULL)
  1285. g_free(component->selected_pair);
  1286. component->selected_pair = NULL;
  1287. if(component->last_seqs_audio)
  1288. janus_seq_list_free(&component->last_seqs_audio);
  1289. if(component->last_seqs_video)
  1290. janus_seq_list_free(&component->last_seqs_video);
  1291. janus_ice_stats_reset(&component->in_stats);
  1292. janus_ice_stats_reset(&component->out_stats);
  1293. g_free(component);
  1294. //~ janus_mutex_unlock(&handle->mutex);
  1295. }
  1296.  
  1297. /* Call plugin slow_link callback if enough NACKs within a second */
  1298. #define SLOW_LINK_NACKS_PER_SEC 8
  1299. static void
  1300. janus_slow_link_update(janus_ice_component *component, janus_ice_handle *handle,
  1301. guint nacks, int video, int uplink, gint64 now ) {
  1302. if(now - component->sl_nack_period_ts > 2 * G_USEC_PER_SEC) {
  1303. /* old nacks too old, don't count them */
  1304. component->sl_nack_period_ts = now;
  1305. component->sl_nack_recent_cnt = 0;
  1306. }
  1307. component->sl_nack_recent_cnt += nacks;
  1308. if(component->sl_nack_recent_cnt >= SLOW_LINK_NACKS_PER_SEC
  1309. && now - component->last_slowlink_time > 1 * G_USEC_PER_SEC) {
  1310. janus_plugin *plugin = (janus_plugin *)handle->app;
  1311. if(plugin && plugin->slow_link && janus_plugin_session_is_alive(handle->app_handle))
  1312. plugin->slow_link(handle->app_handle, uplink, video);
  1313. component->last_slowlink_time = now;
  1314. component->sl_nack_period_ts = now;
  1315. component->sl_nack_recent_cnt = 0;
  1316. }
  1317. }
  1318.  
  1319.  
  1320. /* Callbacks */
  1321. void janus_ice_cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer user_data) {
  1322. janus_ice_handle *handle = (janus_ice_handle *)user_data;
  1323. if(!handle)
  1324. return;
  1325. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Gathering done for stream %d\n", handle->handle_id, stream_id);
  1326. handle->cdone++;
  1327. janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
  1328. if(!stream) {
  1329. JANUS_LOG(LOG_ERR, "[%"SCNu64"] No stream %d??\n", handle->handle_id, stream_id);
  1330. return;
  1331. }
  1332. stream->cdone = 1;
  1333. }
  1334.  
  1335. void janus_ice_cb_component_state_changed(NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer ice) {
  1336. janus_ice_handle *handle = (janus_ice_handle *)ice;
  1337. if(!handle)
  1338. return;
  1339. if(component_id > 1 && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)) {
  1340. /* State changed for a component we don't need anymore (rtcp-mux) */
  1341. return;
  1342. }
  1343. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Component state changed for component %d in stream %d: %d (%s)\n",
  1344. handle->handle_id, component_id, stream_id, state, janus_get_ice_state_name(state));
  1345. janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
  1346. if(!stream) {
  1347. JANUS_LOG(LOG_ERR, "[%"SCNu64"] No stream %d??\n", handle->handle_id, stream_id);
  1348. return;
  1349. }
  1350. janus_ice_component *component = g_hash_table_lookup(stream->components, GUINT_TO_POINTER(component_id));
  1351. if(!component) {
  1352. JANUS_LOG(LOG_ERR, "[%"SCNu64"] No component %d in stream %d??\n", handle->handle_id, component_id, stream_id);
  1353. return;
  1354. }
  1355. component->state = 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. /* Now we can start the DTLS handshake (FIXME This was on the 'connected' state notification, before) */
  1480. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Component is ready enough, starting DTLS handshake...\n", handle->handle_id);
  1481. /* Have we been here before? (might happen, when trickling) */
  1482. if(component->dtls != NULL)
  1483. return;
  1484. component->component_connected = janus_get_monotonic_time();
  1485. /* Create DTLS-SRTP context, at last */
  1486. component->dtls = janus_dtls_srtp_create(component, stream->dtls_role);
  1487. if(!component->dtls) {
  1488. JANUS_LOG(LOG_ERR, "[%"SCNu64"] No component DTLS-SRTP session??\n", handle->handle_id);
  1489. return;
  1490. }
  1491. janus_dtls_srtp_handshake(component->dtls);
  1492. /* Create retransmission timer */
  1493. component->source = g_timeout_source_new(100);
  1494. g_source_set_callback(component->source, janus_dtls_retry, component->dtls, NULL);
  1495. guint id = g_source_attach(component->source, handle->icectx);
  1496. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Creating retransmission timer with ID %u\n", handle->handle_id, id);
  1497. }
  1498.  
  1499. #ifndef HAVE_LIBNICE_TCP
  1500. void janus_ice_cb_new_remote_candidate (NiceAgent *agent, guint stream_id, guint component_id, gchar *foundation, gpointer ice) {
  1501. #else
  1502. void janus_ice_cb_new_remote_candidate (NiceAgent *agent, NiceCandidate *candidate, gpointer ice) {
  1503. #endif
  1504. janus_ice_handle *handle = (janus_ice_handle *)ice;
  1505. #ifndef HAVE_LIBNICE_TCP
  1506. 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);
  1507. #else
  1508. const char *ctype = NULL;
  1509. switch(candidate->type) {
  1510. case NICE_CANDIDATE_TYPE_HOST:
  1511. ctype = "host";
  1512. break;
  1513. case NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE:
  1514. ctype = "srflx";
  1515. break;
  1516. case NICE_CANDIDATE_TYPE_PEER_REFLEXIVE:
  1517. ctype = "prflx";
  1518. break;
  1519. case NICE_CANDIDATE_TYPE_RELAYED:
  1520. ctype = "relay";
  1521. break;
  1522. default:
  1523. break;
  1524. }
  1525. guint stream_id = candidate->stream_id;
  1526. guint component_id = candidate->component_id;
  1527. 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);
  1528. #endif
  1529. if(!handle)
  1530. return;
  1531. if(component_id > 1 && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)) {
  1532. /* New remote candidate for a component we don't need anymore (rtcp-mux) */
  1533. return;
  1534. }
  1535. janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
  1536. if(!stream) {
  1537. JANUS_LOG(LOG_ERR, "[%"SCNu64"] No stream %d??\n", handle->handle_id, stream_id);
  1538. return;
  1539. }
  1540. janus_ice_component *component = g_hash_table_lookup(stream->components, GUINT_TO_POINTER(component_id));
  1541. if(!component) {
  1542. JANUS_LOG(LOG_ERR, "[%"SCNu64"] No component %d in stream %d??\n", handle->handle_id, component_id, stream_id);
  1543. return;
  1544. }
  1545. #ifndef HAVE_LIBNICE_TCP
  1546. /* Get remote candidates and look for the related foundation */
  1547. NiceCandidate *candidate = NULL;
  1548. GSList *candidates = nice_agent_get_remote_candidates(agent, component_id, stream_id), *tmp = candidates;
  1549. while(tmp) {
  1550. NiceCandidate *c = (NiceCandidate *)tmp->data;
  1551. if(candidate == NULL) {
  1552. /* Check if this is what we're looking for */
  1553. if(!strcasecmp(c->foundation, foundation)) {
  1554. /* It is! */
  1555. candidate = c;
  1556. tmp = tmp->next;
  1557. continue;
  1558. }
  1559. }
  1560. nice_candidate_free(c);
  1561. tmp = tmp->next;
  1562. }
  1563. g_slist_free(candidates);
  1564. if(candidate == NULL) {
  1565. JANUS_LOG(LOG_WARN, "Candidate with foundation %s not found?\n", foundation);
  1566. return;
  1567. }
  1568. #endif
  1569. /* Render the candidate and add it to the remote_candidates cache for the admin API */
  1570. if(candidate->type != NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) {
  1571. /* ... but only if it's 'prflx', the others we add ourselves */
  1572. goto candidatedone;
  1573. }
  1574. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Stream #%d, Component #%d\n", handle->handle_id, candidate->stream_id, candidate->component_id);
  1575. gchar address[NICE_ADDRESS_STRING_LEN], base_address[NICE_ADDRESS_STRING_LEN];
  1576. gint port = 0, base_port = 0;
  1577. nice_address_to_string(&(candidate->addr), (gchar *)&address);
  1578. port = nice_address_get_port(&(candidate->addr));
  1579. nice_address_to_string(&(candidate->base_addr), (gchar *)&base_address);
  1580. base_port = nice_address_get_port(&(candidate->base_addr));
  1581. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Address: %s:%d\n", handle->handle_id, address, port);
  1582. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Priority: %d\n", handle->handle_id, candidate->priority);
  1583. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Foundation: %s\n", handle->handle_id, candidate->foundation);
  1584. char buffer[100];
  1585. if(candidate->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
  1586. g_snprintf(buffer, 100,
  1587. "%s %d %s %d %s %d typ prflx raddr %s rport %d\r\n",
  1588. candidate->foundation,
  1589. candidate->component_id,
  1590. "udp",
  1591. candidate->priority,
  1592. address,
  1593. port,
  1594. base_address,
  1595. base_port);
  1596. } else {
  1597. if(!janus_ice_tcp_enabled) {
  1598. /* ICETCP support disabled */
  1599. JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping prflx TCP candidate, ICETCP support disabled...\n", handle->handle_id);
  1600. goto candidatedone;
  1601. }
  1602. #ifndef HAVE_LIBNICE_TCP
  1603. /* TCP candidates are only supported since libnice 0.1.8 */
  1604. JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping prflx TCP candidate, the libnice version doesn't support it...\n", handle->handle_id);
  1605. goto candidatedone;
  1606. #else
  1607. const char *type = NULL;
  1608. switch(candidate->transport) {
  1609. case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
  1610. type = "active";
  1611. break;
  1612. case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
  1613. type = "passive";
  1614. break;
  1615. case NICE_CANDIDATE_TRANSPORT_TCP_SO:
  1616. type = "so";
  1617. break;
  1618. default:
  1619. break;
  1620. }
  1621. if(type == NULL) {
  1622. /* FIXME Unsupported transport */
  1623. JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported transport, skipping nonUDP/TCP prflx candidate...\n", handle->handle_id);
  1624. goto candidatedone;
  1625. } else {
  1626. g_snprintf(buffer, 100,
  1627. "%s %d %s %d %s %d typ prflx raddr %s rport %d tcptype %s\r\n",
  1628. candidate->foundation,
  1629. candidate->component_id,
  1630. "tcp",
  1631. candidate->priority,
  1632. address,
  1633. port,
  1634. base_address,
  1635. base_port,
  1636. type);
  1637. }
  1638. #endif
  1639. }
  1640.  
  1641. /* Save for the summary, in case we need it */
  1642. component->remote_candidates = g_slist_append(component->remote_candidates, g_strdup(buffer));
  1643.  
  1644. candidatedone:
  1645. #ifndef HAVE_LIBNICE_TCP
  1646. nice_candidate_free(candidate);
  1647. #endif
  1648. return;
  1649. }
  1650.  
  1651. void janus_ice_cb_nice_recv(NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer ice) {
  1652. janus_ice_component *component = (janus_ice_component *)ice;
  1653. if(!component) {
  1654. JANUS_LOG(LOG_ERR, "No component %d in stream %d??\n", component_id, stream_id);
  1655. return;
  1656. }
  1657. janus_ice_stream *stream = component->stream;
  1658. if(!stream) {
  1659. JANUS_LOG(LOG_ERR, "No stream %d??\n", stream_id);
  1660. return;
  1661. }
  1662. janus_ice_handle *handle = stream->handle;
  1663. if(!handle) {
  1664. JANUS_LOG(LOG_ERR, "No handle for stream %d??\n", stream_id);
  1665. return;
  1666. }
  1667. if(!component->dtls) { /* Still waiting for the DTLS stack */
  1668. 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);
  1669. return;
  1670. }
  1671.  
  1672. if (janus_is_rtcp(buf)) {
  1673.  
  1674. rtcp_context ctx;
  1675.  
  1676. janus_rtcp_process_incoming_rtp(&ctx, buf, len);
  1677. uint32_t lost = janus_rtcp_context_get_lost(&ctx);
  1678.  
  1679. printf("Lost= %d\n", lost);
  1680. }
  1681.  
  1682. /* What is this? */
  1683. if (janus_is_dtls(buf) || (!janus_is_rtp(buf) && !janus_is_rtcp(buf))) {
  1684. /* This is DTLS: either handshake stuff, or data coming from SCTP DataChannels */
  1685. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Looks like DTLS!\n", handle->handle_id);
  1686. janus_dtls_srtp_incoming_msg(component->dtls, buf, len);
  1687. /* Update stats (TODO Do the same for the last second window as well) */
  1688. component->in_stats.data_packets++;
  1689. component->in_stats.data_bytes += len;
  1690. return;
  1691. }
  1692. /* Not DTLS... RTP or RTCP? (http://tools.ietf.org/html/rfc5761#section-4) */
  1693. if(len < 12)
  1694. return; /* Definitely nothing useful */
  1695. if(component_id == 1 && (!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) || janus_is_rtp(buf))) {
  1696. /* FIXME If rtcp-mux is not used, a first component is always RTP; otherwise, we need to check */
  1697. //~ JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Got an RTP packet (%s stream)!\n", handle->handle_id,
  1698. //~ janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) ? "bundled" : (stream->stream_id == handle->audio_id ? "audio" : "video"));
  1699. if(!component->dtls || !component->dtls->srtp_valid || !component->dtls->srtp_in) {
  1700. JANUS_LOG(LOG_WARN, "[%"SCNu64"] Missing valid SRTP session (packet arrived too early?), skipping...\n", handle->handle_id);
  1701. } else {
  1702. rtp_header *header = (rtp_header *)buf;
  1703. /* Is this audio or video? */
  1704. int video = 0;
  1705. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE)) {
  1706. /* Easy enough */
  1707. video = (stream->stream_id == handle->video_id ? 1 : 0);
  1708. } else {
  1709. /* Bundled streams, check SSRC */
  1710. guint32 packet_ssrc = ntohl(header->ssrc);
  1711. video = ((stream->video_ssrc_peer == packet_ssrc || stream->video_ssrc_peer_rtx == packet_ssrc) ? 1 : 0);
  1712. if(!video && stream->audio_ssrc_peer != packet_ssrc) {
  1713. /* FIXME In case it happens, we should check what it is */
  1714. if(stream->audio_ssrc_peer == 0 || stream->video_ssrc_peer == 0) {
  1715. /* Apparently we were not told the peer SSRCs, try to guess from the payload type */
  1716. gboolean found = FALSE;
  1717. guint16 pt = header->type;
  1718. if(stream->audio_ssrc_peer == 0 && stream->audio_payload_types) {
  1719. GList *pts = stream->audio_payload_types;
  1720. while(pts) {
  1721. guint16 audio_pt = GPOINTER_TO_UINT(pts->data);
  1722. if(pt == audio_pt) {
  1723. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Unadvertized SSRC (%"SCNu32") is audio! (payload type %"SCNu16")\n", handle->handle_id, packet_ssrc, pt);
  1724. video = 0;
  1725. stream->audio_ssrc_peer = packet_ssrc;
  1726. found = TRUE;
  1727. break;
  1728. }
  1729. pts = pts->next;
  1730. }
  1731. }
  1732. if(!found && stream->video_ssrc_peer == 0 && stream->video_payload_types) {
  1733. GList *pts = stream->video_payload_types;
  1734. while(pts) {
  1735. guint16 video_pt = GPOINTER_TO_UINT(pts->data);
  1736. if(pt == video_pt) {
  1737. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Unadvertized SSRC (%"SCNu32") is video! (payload type %"SCNu16")\n", handle->handle_id, packet_ssrc, pt);
  1738. video = 1;
  1739. stream->video_ssrc_peer = packet_ssrc;
  1740. found = TRUE;
  1741. break;
  1742. }
  1743. pts = pts->next;
  1744. }
  1745. }
  1746. }
  1747. if(!video && stream->audio_ssrc_peer != packet_ssrc) {
  1748. JANUS_LOG(LOG_WARN, "[%"SCNu64"] Not video and not audio? dropping (SSRC %"SCNu32")...\n", handle->handle_id, packet_ssrc);
  1749. return;
  1750. }
  1751. }
  1752. if(stream->video_ssrc_peer_rtx == packet_ssrc) {
  1753. /* FIXME This is a video retransmission: set the regular peer SSRC so
  1754. * that we avoid outgoing SRTP errors in case we got the packet already */
  1755. header->ssrc = htonl(stream->video_ssrc_peer);
  1756. }
  1757. //~ JANUS_LOG(LOG_VERB, "[RTP] Bundling: this is %s (video=%"SCNu64", audio=%"SCNu64", got %ld)\n",
  1758. //~ video ? "video" : "audio", stream->video_ssrc_peer, stream->audio_ssrc_peer, ntohl(header->ssrc));
  1759. }
  1760.  
  1761. int buflen = len;
  1762. err_status_t res = srtp_unprotect(component->dtls->srtp_in, buf, &buflen);
  1763. if(res != err_status_ok) {
  1764. if(res != err_status_replay_fail && res != err_status_replay_old) {
  1765. /* 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) */
  1766. rtp_header *header = (rtp_header *)buf;
  1767. guint32 timestamp = ntohl(header->timestamp);
  1768. guint16 seq = ntohs(header->seq_number);
  1769. 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);
  1770. }
  1771. } else {
  1772. if(video) {
  1773. if(stream->video_ssrc_peer == 0) {
  1774. stream->video_ssrc_peer = ntohl(header->ssrc);
  1775. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Peer video SSRC: %u\n", handle->handle_id, stream->video_ssrc_peer);
  1776. }
  1777. } else {
  1778. if(stream->audio_ssrc_peer == 0) {
  1779. stream->audio_ssrc_peer = ntohl(header->ssrc);
  1780. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Peer audio SSRC: %u\n", handle->handle_id, stream->audio_ssrc_peer);
  1781. }
  1782. }
  1783. /* Pass the data to the responsible plugin */
  1784. janus_plugin *plugin = (janus_plugin *)handle->app;
  1785. if(plugin && plugin->incoming_rtp)
  1786. plugin->incoming_rtp(handle->app_handle, video, buf, buflen);
  1787. /* Update stats (TODO Do the same for the last second window as well) */
  1788. if(buflen > 0) {
  1789. /* Update the last sec queue as well */
  1790. janus_ice_stats_item *s = g_malloc0(sizeof(janus_ice_stats_item));
  1791. s->bytes = buflen;
  1792. s->when = janus_get_monotonic_time();
  1793. janus_mutex_lock(&component->mutex);
  1794. if(!video) {
  1795. if(component->in_stats.audio_bytes == 0 || component->in_stats.audio_notified_lastsec) {
  1796. /* We either received our first audio packet, or we started receiving it again after missing more than a second */
  1797. component->in_stats.audio_notified_lastsec = FALSE;
  1798. janus_ice_notify_media(handle, FALSE, TRUE);
  1799. }
  1800. component->in_stats.audio_packets++;
  1801. component->in_stats.audio_bytes += buflen;
  1802. component->in_stats.audio_bytes_lastsec = g_list_append(component->in_stats.audio_bytes_lastsec, s);
  1803. if(g_list_length(component->in_stats.audio_bytes_lastsec) > 100) {
  1804. GList *first = g_list_first(component->in_stats.audio_bytes_lastsec);
  1805. s = (janus_ice_stats_item *)first->data;
  1806. first->data = NULL;
  1807. component->in_stats.audio_bytes_lastsec = g_list_delete_link(component->in_stats.audio_bytes_lastsec, first);
  1808. g_free(s);
  1809. }
  1810. } else {
  1811. if(component->in_stats.video_bytes == 0 || component->in_stats.video_notified_lastsec) {
  1812. /* We either received our first video packet, or we started receiving it again after missing more than a second */
  1813. component->in_stats.video_notified_lastsec = FALSE;
  1814. janus_ice_notify_media(handle, TRUE, TRUE);
  1815. }
  1816. component->in_stats.video_packets++;
  1817. component->in_stats.video_bytes += buflen;
  1818. component->in_stats.video_bytes_lastsec = g_list_append(component->in_stats.video_bytes_lastsec, s);
  1819. if(g_list_length(component->in_stats.video_bytes_lastsec) > 100) {
  1820. GList *first = g_list_first(component->in_stats.video_bytes_lastsec);
  1821. s = (janus_ice_stats_item *)first->data;
  1822. first->data = NULL;
  1823. component->in_stats.video_bytes_lastsec = g_list_delete_link(component->in_stats.video_bytes_lastsec, first);
  1824. g_free(s);
  1825. }
  1826. }
  1827. janus_mutex_unlock(&component->mutex);
  1828. }
  1829.  
  1830. /* Update the RTCP context as well */
  1831. rtcp_context *rtcp_ctx = video ? stream->video_rtcp_ctx : stream->audio_rtcp_ctx;
  1832. janus_rtcp_process_incoming_rtp(rtcp_ctx, buf, buflen);
  1833.  
  1834. /* Keep track of RTP sequence numbers, in case we need to NACK them */
  1835. /* Note: unsigned int overflow/underflow wraps (defined behavior) */
  1836. guint16 new_seqn = ntohs(header->seq_number);
  1837. guint16 cur_seqn;
  1838. int last_seqs_len = 0;
  1839. janus_mutex_lock(&component->mutex);
  1840. seq_info_t **last_seqs = video ? &component->last_seqs_video : &component->last_seqs_audio;
  1841. seq_info_t *cur_seq = *last_seqs;
  1842. if(cur_seq) {
  1843. cur_seq = cur_seq->prev;
  1844. cur_seqn = cur_seq->seq;
  1845. } else {
  1846. /* First seq, set up to add one seq */
  1847. cur_seqn = new_seqn - (guint16)1; /* Can wrap */
  1848. }
  1849. if(!janus_seq_in_range(new_seqn, cur_seqn, LAST_SEQS_MAX_LEN) &&
  1850. !janus_seq_in_range(cur_seqn, new_seqn, 1000)) {
  1851. /* Jump too big, start fresh */
  1852. JANUS_LOG(LOG_WARN, "[%"SCNu64"] Big sequence number jump %hu -> %hu (%s stream)\n",
  1853. handle->handle_id, cur_seqn, new_seqn, video ? "video" : "audio");
  1854. janus_seq_list_free(last_seqs);
  1855. cur_seq = NULL;
  1856. cur_seqn = new_seqn - (guint16)1;
  1857. }
  1858.  
  1859. GSList *nacks = NULL;
  1860. gint64 now = janus_get_monotonic_time();
  1861.  
  1862. if(janus_seq_in_range(new_seqn, cur_seqn, LAST_SEQS_MAX_LEN)) {
  1863. /* Add new seq objs forward */
  1864. while(cur_seqn != new_seqn) {
  1865. cur_seqn += (guint16)1; /* can wrap */
  1866. seq_info_t *seq_obj = g_malloc0(sizeof(seq_info_t));
  1867. seq_obj->seq = cur_seqn;
  1868. seq_obj->ts = now;
  1869. seq_obj->state = (cur_seqn == new_seqn) ? SEQ_RECVED : SEQ_MISSING;
  1870. janus_seq_append(last_seqs, seq_obj);
  1871. last_seqs_len++;
  1872. }
  1873. }
  1874. if(cur_seq) {
  1875. /* Scan old seq objs backwards */
  1876. for (;;) {
  1877. last_seqs_len++;
  1878. if(cur_seq->seq == new_seqn) {
  1879. JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Recieved missed sequence number %"SCNu16"\n", handle->handle_id, cur_seq->seq);
  1880. cur_seq->state = SEQ_RECVED;
  1881. } else if(cur_seq->state == SEQ_MISSING && now - cur_seq->ts > SEQ_MISSING_WAIT) {
  1882. JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Missed sequence number %"SCNu16", sending 1st NACK\n", handle->handle_id, cur_seq->seq);
  1883. nacks = g_slist_append(nacks, GUINT_TO_POINTER(cur_seq->seq));
  1884. cur_seq->state = SEQ_NACKED;
  1885. } else if(cur_seq->state == SEQ_NACKED && now - cur_seq->ts > SEQ_NACKED_WAIT) {
  1886. JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Missed sequence number %"SCNu16", sending 2nd NACK\n", handle->handle_id, cur_seq->seq);
  1887. nacks = g_slist_append(nacks, GUINT_TO_POINTER(cur_seq->seq));
  1888. cur_seq->state = SEQ_GIVEUP;
  1889. }
  1890. if(cur_seq == *last_seqs) {
  1891. /* Just processed head */
  1892. break;
  1893. }
  1894. cur_seq = cur_seq->prev;
  1895. }
  1896. }
  1897. while(last_seqs_len > LAST_SEQS_MAX_LEN) {
  1898. seq_info_t *node = janus_seq_pop_head(last_seqs);
  1899. g_free(node);
  1900. last_seqs_len--;
  1901. }
  1902.  
  1903. guint nacks_count = g_slist_length(nacks);
  1904. if(nacks_count) {
  1905. /* Generate a NACK and send it */
  1906. JANUS_LOG(LOG_DBG, "[%"SCNu64"] now sending NACK for %u missed packets\n", handle->handle_id, nacks_count);
  1907. char nackbuf[120];
  1908. int res = janus_rtcp_nacks(nackbuf, sizeof(nackbuf), nacks);
  1909. if(res > 0)
  1910. janus_ice_relay_rtcp(handle, video, nackbuf, res);
  1911. /* Update stats */
  1912. component->nack_sent_recent_cnt += nacks_count;
  1913. if(video) {
  1914. component->out_stats.video_nacks += nacks_count;
  1915. } else {
  1916. component->out_stats.audio_nacks += nacks_count;
  1917. }
  1918. /* Inform the plugin about the slow downlink in case it's needed */
  1919. janus_slow_link_update(component, handle, nacks_count, video, 0, now);
  1920. }
  1921. if (component->nack_sent_recent_cnt &&
  1922. now - component->nack_sent_log_ts > 5 * G_USEC_PER_SEC) {
  1923. JANUS_LOG(LOG_VERB, "[%10"SCNu64"] sent NACKs for %u missing packets\n",
  1924. handle->handle_id, component->nack_sent_recent_cnt);
  1925. component->nack_sent_recent_cnt = 0;
  1926. component->nack_sent_log_ts = now;
  1927. }
  1928. janus_mutex_unlock(&component->mutex);
  1929. g_slist_free(nacks);
  1930. nacks = NULL;
  1931. }
  1932. }
  1933. return;
  1934. }
  1935. if(component_id == 2 || (component_id == 1 && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) && janus_is_rtcp(buf))) {
  1936. /* FIXME A second component is always RTCP; in case of rtcp-mux, we need to check */
  1937. JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Got an RTCP packet (%s stream)!\n", handle->handle_id,
  1938. janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) ? "bundled" : (stream->stream_id == handle->audio_id ? "audio" : "video"));
  1939. if(!component->dtls || !component->dtls->srtp_valid || !component->dtls->srtp_in) {
  1940. JANUS_LOG(LOG_WARN, "[%"SCNu64"] Missing valid SRTP session (packet arrived too early?), skipping...\n", handle->handle_id);
  1941. } else {
  1942. int buflen = len;
  1943. err_status_t res = srtp_unprotect_rtcp(component->dtls->srtp_in, buf, &buflen);
  1944. if(res != err_status_ok) {
  1945. JANUS_LOG(LOG_ERR, "[%"SCNu64"] SRTCP unprotect error: %s (len=%d-->%d)\n", handle->handle_id, janus_get_srtp_error(res), len, buflen);
  1946. } else {
  1947. /* Is this audio or video? */
  1948. int video = 0;
  1949. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE)) {
  1950. /* Easy enough */
  1951. video = (stream->stream_id == handle->video_id ? 1 : 0);
  1952. } else {
  1953. /* Bundled streams, should we check the SSRCs? */
  1954. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO)) {
  1955. /* No audio has been negotiated, definitely video */
  1956. JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is video (no audio has been negotiated)\n", handle->handle_id);
  1957. video = 1;
  1958. } else if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO)) {
  1959. /* No video has been negotiated, definitely audio */
  1960. JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is audio (no video has been negotiated)\n", handle->handle_id);
  1961. video = 0;
  1962. } else {
  1963. if(stream->audio_ssrc_peer == 0 || stream->video_ssrc_peer == 0) {
  1964. /* We don't know the remote SSRC: this can happen for recvonly clients
  1965. * (see https://groups.google.com/forum/#!topic/discuss-webrtc/5yuZjV7lkNc)
  1966. * Check the local SSRC, compare it to what we have */
  1967. guint32 rtcp_ssrc = janus_rtcp_get_receiver_ssrc(buf, len);
  1968. if(rtcp_ssrc == stream->audio_ssrc) {
  1969. video = 0;
  1970. } else if(rtcp_ssrc == stream->video_ssrc) {
  1971. video = 1;
  1972. } else {
  1973. /* Mh, no SR or RR? Try checking if there's any FIR, PLI or REMB */
  1974. if(janus_rtcp_has_fir(buf, len) || janus_rtcp_has_pli(buf, len) || janus_rtcp_get_remb(buf, len)) {
  1975. video = 1;
  1976. }
  1977. }
  1978. JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is %s (local SSRC: video=%"SCNu32", audio=%"SCNu32", got %"SCNu32")\n",
  1979. handle->handle_id, video ? "video" : "audio", stream->video_ssrc, stream->audio_ssrc, rtcp_ssrc);
  1980. } else {
  1981. /* Check the remote SSRC, compare it to what we have */
  1982. guint32 rtcp_ssrc = janus_rtcp_get_sender_ssrc(buf, len);
  1983. video = (stream->video_ssrc_peer == rtcp_ssrc ? 1 : 0);
  1984. JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Incoming RTCP, bundling: this is %s (remote SSRC: video=%"SCNu32", audio=%"SCNu32", got %"SCNu32")\n",
  1985. handle->handle_id, video ? "video" : "audio", stream->video_ssrc_peer, stream->audio_ssrc_peer, rtcp_ssrc);
  1986. }
  1987. }
  1988. }
  1989. /* Let's process this RTCP (compound?) packet, and update the RTCP context for this stream in case */
  1990. rtcp_context *rtcp_ctx = video ? stream->video_rtcp_ctx : stream->audio_rtcp_ctx;
  1991. janus_rtcp_parse(rtcp_ctx, buf, buflen);
  1992.  
  1993. /* Now let's see if there are any NACKs to handle */
  1994. gint64 now = janus_get_monotonic_time();
  1995. GSList *nacks = janus_rtcp_get_nacks(buf, buflen);
  1996. guint nacks_count = g_slist_length(nacks);
  1997. if(nacks_count) {
  1998. /* Handle NACK */
  1999. JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Just got some NACKS (%d) we should handle...\n", handle->handle_id, nacks_count);
  2000. GSList *list = nacks;
  2001. int retransmits_cnt = 0;
  2002. janus_mutex_lock(&component->mutex);
  2003. while(list) {
  2004. unsigned int seqnr = GPOINTER_TO_UINT(list->data);
  2005. JANUS_LOG(LOG_DBG, "[%"SCNu64"] >> %u\n", handle->handle_id, seqnr);
  2006. GList *rp = component->retransmit_buffer;
  2007. while(rp) {
  2008. janus_rtp_packet *p = (janus_rtp_packet *)rp->data;
  2009. if(p) {
  2010. rtp_header *rh = (rtp_header *)p->data;
  2011. if(ntohs(rh->seq_number) == seqnr) {
  2012. /* Should we retransmit this packet? */
  2013. if((p->last_retransmit > 0) && (now-p->last_retransmit < MAX_NACK_IGNORE)) {
  2014. JANUS_LOG(LOG_HUGE, "[%"SCNu64"] >> >> Packet %u was retransmitted just %"SCNi64"ms ago, skipping\n", handle->handle_id, seqnr, now-p->last_retransmit);
  2015. break;
  2016. }
  2017. JANUS_LOG(LOG_HUGE, "[%"SCNu64"] >> >> Scheduling %u for retransmission due to NACK\n", handle->handle_id, seqnr);
  2018. p->last_retransmit = now;
  2019. retransmits_cnt++;
  2020. /* Enqueue it */
  2021. janus_ice_queued_packet *pkt = (janus_ice_queued_packet *)g_malloc0(sizeof(janus_ice_queued_packet));
  2022. pkt->data = g_malloc0(p->length);
  2023. memcpy(pkt->data, p->data, p->length);
  2024. pkt->length = p->length;
  2025. pkt->type = video ? JANUS_ICE_PACKET_VIDEO : JANUS_ICE_PACKET_AUDIO;
  2026. pkt->control = FALSE;
  2027. pkt->encrypted = TRUE; /* This was already encrypted before */
  2028. if(handle->queued_packets != NULL)
  2029. g_async_queue_push(handle->queued_packets, pkt);
  2030. break;
  2031. }
  2032. }
  2033. rp = rp->next;
  2034. }
  2035. list = list->next;
  2036. }
  2037. component->retransmit_recent_cnt += retransmits_cnt;
  2038. /* FIXME Remove the NACK compound packet, we've handled it */
  2039. buflen = janus_rtcp_remove_nacks(buf, buflen);
  2040. /* Update stats */
  2041. if(video) {
  2042. component->in_stats.video_nacks += nacks_count;
  2043. } else {
  2044. component->in_stats.audio_nacks += nacks_count;
  2045. }
  2046. /* Inform the plugin about the slow uplink in case it's needed */
  2047. janus_slow_link_update(component, handle, retransmits_cnt, video, 1, now);
  2048. janus_mutex_unlock(&component->mutex);
  2049. g_slist_free(nacks);
  2050. nacks = NULL;
  2051. }
  2052. if (component->retransmit_recent_cnt &&
  2053. now - component->retransmit_log_ts > 5 * G_USEC_PER_SEC) {
  2054. JANUS_LOG(LOG_VERB, "[%10"SCNu64"] retransmitted %u packets due to NACK\n",
  2055. handle->handle_id, component->retransmit_recent_cnt);
  2056. component->retransmit_recent_cnt = 0;
  2057. component->retransmit_log_ts = now;
  2058. }
  2059.  
  2060. janus_plugin *plugin = (janus_plugin *)handle->app;
  2061. if(plugin && plugin->incoming_rtcp)
  2062. plugin->incoming_rtcp(handle->app_handle, video, buf, buflen);
  2063. }
  2064. }
  2065. return;
  2066. }
  2067. if(component_id == 3 || (janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)
  2068. && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS))) {
  2069. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Not RTP and not RTCP... may these be data channels?\n", handle->handle_id);
  2070. janus_dtls_srtp_incoming_msg(component->dtls, buf, len);
  2071. /* Update stats (TODO Do the same for the last second window as well) */
  2072. if(len > 0) {
  2073. component->in_stats.data_packets++;
  2074. component->in_stats.data_bytes += len;
  2075. }
  2076. return;
  2077. }
  2078. }
  2079.  
  2080. void janus_ice_incoming_data(janus_ice_handle *handle, char *buffer, int length) {
  2081. if(handle == NULL || buffer == NULL || length <= 0)
  2082. return;
  2083. janus_plugin *plugin = (janus_plugin *)handle->app;
  2084. if(plugin && plugin->incoming_data)
  2085. plugin->incoming_data(handle->app_handle, buffer, length);
  2086. }
  2087.  
  2088.  
  2089. /* Thread to create agent */
  2090. void *janus_ice_thread(void *data) {
  2091. janus_ice_handle *handle = data;
  2092. JANUS_LOG(LOG_VERB, "[%"SCNu64"] ICE thread started\n", handle->handle_id);
  2093. GMainLoop *loop = handle->iceloop;
  2094. if(loop == NULL) {
  2095. JANUS_LOG(LOG_ERR, "[%"SCNu64"] Invalid loop...\n", handle->handle_id);
  2096. g_thread_unref(g_thread_self());
  2097. return NULL;
  2098. }
  2099. g_usleep (100000);
  2100. JANUS_LOG(LOG_DBG, "[%"SCNu64"] Looping (ICE)...\n", handle->handle_id);
  2101. g_main_loop_run (loop);
  2102. janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING);
  2103. if(handle->cdone == 0)
  2104. handle->cdone = -1;
  2105. JANUS_LOG(LOG_VERB, "[%"SCNu64"] ICE thread ended!\n", handle->handle_id);
  2106. /* This handle has been destroyed, wait a bit and then free all the resources */
  2107. g_usleep (1*G_USEC_PER_SEC);
  2108. if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP)) {
  2109. //~ janus_ice_free(handle);
  2110. } else {
  2111. janus_ice_webrtc_free(handle);
  2112. }
  2113. g_thread_unref(g_thread_self());
  2114. return NULL;
  2115. }
  2116.  
  2117. /* Helper: candidates */
  2118. void janus_ice_candidates_to_sdp(janus_ice_handle *handle, char *sdp, guint stream_id, guint component_id)
  2119. {
  2120. if(!handle || !handle->agent || !sdp)
  2121. return;
  2122. janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
  2123. if(!stream) {
  2124. JANUS_LOG(LOG_ERR, "[%"SCNu64"] No stream %d??\n", handle->handle_id, stream_id);
  2125. return;
  2126. }
  2127. janus_ice_component *component = g_hash_table_lookup(stream->components, GUINT_TO_POINTER(component_id));
  2128. if(!component) {
  2129. JANUS_LOG(LOG_ERR, "[%"SCNu64"] No component %d in stream %d??\n", handle->handle_id, component_id, stream_id);
  2130. return;
  2131. }
  2132. NiceAgent* agent = handle->agent;
  2133. /* adding a stream should cause host candidates to be generated */
  2134. char *host_ip = NULL;
  2135. if(nat_1_1_enabled) {
  2136. /* A 1:1 NAT mapping was specified, overwrite all the host addresses with the public IP */
  2137. host_ip = janus_get_public_ip();
  2138. 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);
  2139. }
  2140. GSList *candidates, *i;
  2141. candidates = nice_agent_get_local_candidates (agent, stream_id, component_id);
  2142. 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);
  2143. gboolean log_candidates = (component->local_candidates == NULL);
  2144. for (i = candidates; i; i = i->next) {
  2145. NiceCandidate *c = (NiceCandidate *) i->data;
  2146. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Stream #%d, Component #%d\n", handle->handle_id, c->stream_id, c->component_id);
  2147. gchar address[NICE_ADDRESS_STRING_LEN], base_address[NICE_ADDRESS_STRING_LEN];
  2148. gint port = 0, base_port = 0;
  2149. nice_address_to_string(&(c->addr), (gchar *)&address);
  2150. port = nice_address_get_port(&(c->addr));
  2151. nice_address_to_string(&(c->base_addr), (gchar *)&base_address);
  2152. base_port = nice_address_get_port(&(c->base_addr));
  2153. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Address: %s:%d\n", handle->handle_id, address, port);
  2154. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Priority: %d\n", handle->handle_id, c->priority);
  2155. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Foundation: %s\n", handle->handle_id, c->foundation);
  2156. /* SDP time */
  2157. gchar buffer[100];
  2158. if(c->type == NICE_CANDIDATE_TYPE_HOST) {
  2159. /* 'host' candidate */
  2160. if(c->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
  2161. g_snprintf(buffer, 100,
  2162. "a=candidate:%s %d %s %d %s %d typ host\r\n",
  2163. c->foundation,
  2164. c->component_id,
  2165. "udp",
  2166. c->priority,
  2167. host_ip ? host_ip : address,
  2168. port);
  2169. } else {
  2170. if(!janus_ice_tcp_enabled) {
  2171. /* ICE-TCP support disabled */
  2172. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping host TCP candidate, ICE-TCP support disabled...\n", handle->handle_id);
  2173. nice_candidate_free(c);
  2174. continue;
  2175. }
  2176. #ifndef HAVE_LIBNICE_TCP
  2177. /* TCP candidates are only supported since libnice 0.1.8 */
  2178. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping host TCP candidate, the libnice version doesn't support it...\n", handle->handle_id);
  2179. nice_candidate_free(c);
  2180. continue;
  2181. #else
  2182. const char *type = NULL;
  2183. switch(c->transport) {
  2184. case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
  2185. type = "active";
  2186. break;
  2187. case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
  2188. type = "passive";
  2189. break;
  2190. case NICE_CANDIDATE_TRANSPORT_TCP_SO:
  2191. type = "so";
  2192. break;
  2193. default:
  2194. break;
  2195. }
  2196. if(type == NULL) {
  2197. /* FIXME Unsupported transport */
  2198. JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported transport, skipping non-UDP/TCP host candidate...\n", handle->handle_id);
  2199. nice_candidate_free(c);
  2200. continue;
  2201. } else {
  2202. g_snprintf(buffer, 100,
  2203. "a=candidate:%s %d %s %d %s %d typ host tcptype %s\r\n",
  2204. c->foundation,
  2205. c->component_id,
  2206. "tcp",
  2207. c->priority,
  2208. host_ip ? host_ip : address,
  2209. port,
  2210. type);
  2211. }
  2212. #endif
  2213. }
  2214. } else if(c->type == NICE_CANDIDATE_TYPE_SERVER_REFLEXIVE) {
  2215. /* 'srflx' candidate */
  2216. if(c->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
  2217. nice_address_to_string(&(c->base_addr), (gchar *)&base_address);
  2218. gint base_port = nice_address_get_port(&(c->base_addr));
  2219. g_snprintf(buffer, 100,
  2220. "a=candidate:%s %d %s %d %s %d typ srflx raddr %s rport %d\r\n",
  2221. c->foundation,
  2222. c->component_id,
  2223. "udp",
  2224. c->priority,
  2225. address,
  2226. port,
  2227. base_address,
  2228. base_port);
  2229. } else {
  2230. if(!janus_ice_tcp_enabled) {
  2231. /* ICE-TCP support disabled */
  2232. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping srflx TCP candidate, ICE-TCP support disabled...\n", handle->handle_id);
  2233. nice_candidate_free(c);
  2234. continue;
  2235. }
  2236. #ifndef HAVE_LIBNICE_TCP
  2237. /* TCP candidates are only supported since libnice 0.1.8 */
  2238. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping srflx TCP candidate, the libnice version doesn't support it...\n", handle->handle_id);
  2239. nice_candidate_free(c);
  2240. continue;
  2241. #else
  2242. const char *type = NULL;
  2243. switch(c->transport) {
  2244. case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
  2245. type = "active";
  2246. break;
  2247. case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
  2248. type = "passive";
  2249. break;
  2250. case NICE_CANDIDATE_TRANSPORT_TCP_SO:
  2251. type = "so";
  2252. break;
  2253. default:
  2254. break;
  2255. }
  2256. if(type == NULL) {
  2257. /* FIXME Unsupported transport */
  2258. JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported transport, skipping non-UDP/TCP srflx candidate...\n", handle->handle_id);
  2259. nice_candidate_free(c);
  2260. continue;
  2261. } else {
  2262. g_snprintf(buffer, 100,
  2263. "a=candidate:%s %d %s %d %s %d typ srflx raddr %s rport %d tcptype %s\r\n",
  2264. c->foundation,
  2265. c->component_id,
  2266. "tcp",
  2267. c->priority,
  2268. address,
  2269. port,
  2270. base_address,
  2271. base_port,
  2272. type);
  2273. }
  2274. #endif
  2275. }
  2276. } else if(c->type == NICE_CANDIDATE_TYPE_PEER_REFLEXIVE) {
  2277. /* 'prflx' candidate: skip it, we don't add them to the SDP */
  2278. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping prflx candidate...\n", handle->handle_id);
  2279. nice_candidate_free(c);
  2280. continue;
  2281. } else if(c->type == NICE_CANDIDATE_TYPE_RELAYED) {
  2282. /* 'relay' candidate */
  2283. if(c->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
  2284. g_snprintf(buffer, 100,
  2285. "a=candidate:%s %d %s %d %s %d typ relay raddr %s rport %d\r\n",
  2286. c->foundation,
  2287. c->component_id,
  2288. "udp",
  2289. c->priority,
  2290. address,
  2291. port,
  2292. base_address,
  2293. base_port);
  2294. } else {
  2295. if(!janus_ice_tcp_enabled) {
  2296. /* ICE-TCP support disabled */
  2297. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping relay TCP candidate, ICE-TCP support disabled...\n", handle->handle_id);
  2298. nice_candidate_free(c);
  2299. continue;
  2300. }
  2301. #ifndef HAVE_LIBNICE_TCP
  2302. /* TCP candidates are only supported since libnice 0.1.8 */
  2303. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Skipping relay TCP candidate, the libnice version doesn't support it...\n", handle->handle_id);
  2304. nice_candidate_free(c);
  2305. continue;
  2306. #else
  2307. const char *type = NULL;
  2308. switch(c->transport) {
  2309. case NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE:
  2310. type = "active";
  2311. break;
  2312. case NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE:
  2313. type = "passive";
  2314. break;
  2315. case NICE_CANDIDATE_TRANSPORT_TCP_SO:
  2316. type = "so";
  2317. break;
  2318. default:
  2319. break;
  2320. }
  2321. if(type == NULL) {
  2322. /* FIXME Unsupported transport */
  2323. JANUS_LOG(LOG_WARN, "[%"SCNu64"] Unsupported transport, skipping non-UDP/TCP relay candidate...\n", handle->handle_id);
  2324. nice_candidate_free(c);
  2325. continue;
  2326. } else {
  2327. g_snprintf(buffer, 100,
  2328. "a=candidate:%s %d %s %d %s %d typ relay raddr %s rport %d tcptype %s\r\n",
  2329. c->foundation,
  2330. c->component_id,
  2331. "tcp",
  2332. c->priority,
  2333. address,
  2334. port,
  2335. base_address,
  2336. base_port,
  2337. type);
  2338. }
  2339. #endif
  2340. }
  2341. }
  2342. g_strlcat(sdp, buffer, JANUS_BUFSIZE);
  2343. JANUS_LOG(LOG_VERB, "[%"SCNu64"] %s", handle->handle_id, buffer); /* buffer already newline terminated */
  2344. if(log_candidates) {
  2345. /* Save for the summary, in case we need it */
  2346. component->local_candidates = g_slist_append(component->local_candidates, g_strdup(buffer+strlen("a=candidate:")));
  2347. }
  2348. nice_candidate_free(c);
  2349. }
  2350. g_slist_free(candidates);
  2351. }
  2352.  
  2353. void janus_ice_setup_remote_candidates(janus_ice_handle *handle, guint stream_id, guint component_id) {
  2354. if(!handle || !handle->agent || !handle->streams)
  2355. return;
  2356. janus_ice_stream *stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(stream_id));
  2357. if(!stream || !stream->components) {
  2358. JANUS_LOG(LOG_ERR, "[%"SCNu64"] No such stream %d: cannot setup remote candidates for component %d\n", handle->handle_id, stream_id, component_id);
  2359. return;
  2360. }
  2361. if(stream->disabled) {
  2362. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Stream %d is disabled, skipping remote candidates for component %d\n", handle->handle_id, stream_id, component_id);
  2363. return;
  2364. }
  2365. janus_ice_component *component = g_hash_table_lookup(stream->components, GUINT_TO_POINTER(component_id));
  2366. if(!component) {
  2367. JANUS_LOG(LOG_ERR, "[%"SCNu64"] No such component %d in stream %d: cannot setup remote candidates\n", handle->handle_id, component_id, stream_id);
  2368. return;
  2369. }
  2370. if(component->process_started) {
  2371. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Component %d in stream %d has already been set up\n", handle->handle_id, component_id, stream_id);
  2372. return;
  2373. }
  2374. if(!component->candidates || !component->candidates->data) {
  2375. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE)
  2376. || janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES)) {
  2377. 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);
  2378. }
  2379. return;
  2380. }
  2381. JANUS_LOG(LOG_VERB, "[%"SCNu64"] ## Setting remote candidates: stream %d, component %d (%u in the list)\n",
  2382. handle->handle_id, stream_id, component_id, g_slist_length(component->candidates));
  2383. /* Add all candidates */
  2384. NiceCandidate *c = NULL;
  2385. GSList *gsc = component->candidates;
  2386. gchar *rufrag = NULL, *rpwd = NULL;
  2387. while(gsc) {
  2388. c = (NiceCandidate *) gsc->data;
  2389. JANUS_LOG(LOG_VERB, "[%"SCNu64"] >> Remote Stream #%d, Component #%d\n", handle->handle_id, c->stream_id, c->component_id);
  2390. if(c->username && !rufrag)
  2391. rufrag = c->username;
  2392. if(c->password && !rpwd)
  2393. rpwd = c->password;
  2394. gchar address[NICE_ADDRESS_STRING_LEN];
  2395. nice_address_to_string(&(c->addr), (gchar *)&address);
  2396. gint port = nice_address_get_port(&(c->addr));
  2397. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Address: %s:%d\n", handle->handle_id, address, port);
  2398. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Priority: %d\n", handle->handle_id, c->priority);
  2399. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Foundation: %s\n", handle->handle_id, c->foundation);
  2400. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Username: %s\n", handle->handle_id, c->username);
  2401. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Password: %s\n", handle->handle_id, c->password);
  2402. gsc = gsc->next;
  2403. }
  2404. if(rufrag && rpwd) {
  2405. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Setting remote credentials...\n", handle->handle_id);
  2406. if(!nice_agent_set_remote_credentials(handle->agent, stream_id, rufrag, rpwd)) {
  2407. JANUS_LOG(LOG_ERR, "[%"SCNu64"] failed to set remote credentials!\n", handle->handle_id);
  2408. }
  2409. }
  2410. guint added = nice_agent_set_remote_candidates(handle->agent, stream_id, component_id, component->candidates);
  2411. if(added < g_slist_length(component->candidates)) {
  2412. JANUS_LOG(LOG_ERR, "[%"SCNu64"] Failed to set remote candidates :-( (added %u, expected %u)\n",
  2413. handle->handle_id, added, g_slist_length(component->candidates));
  2414. } else {
  2415. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Remote candidates set!\n", handle->handle_id);
  2416. component->process_started = TRUE;
  2417. }
  2418. }
  2419.  
  2420. int janus_ice_setup_local(janus_ice_handle *handle, int offer, int audio, int video, int data, int bundle, int rtcpmux, int trickle) {
  2421. if(!handle)
  2422. return -1;
  2423. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Setting ICE locally: got %s (%d audios, %d videos)\n", handle->handle_id, offer ? "OFFER" : "ANSWER", audio, video);
  2424. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_START);
  2425. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY);
  2426. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP);
  2427. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT);
  2428. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING);
  2429. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO);
  2430. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO);
  2431.  
  2432. /* Note: in case this is not an OFFER, we don't know whether any medium are supported on the other side or not yet */
  2433. if(audio) {
  2434. janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO);
  2435. } else {
  2436. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO);
  2437. }
  2438. if(video) {
  2439. janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO);
  2440. } else {
  2441. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO);
  2442. }
  2443. if(data) {
  2444. janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS);
  2445. } else {
  2446. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS);
  2447. }
  2448. /* Note: in case this is not an OFFER, we don't know whether BUNDLE is supported on the other side or not yet,
  2449. * unless Janus was configured to force BUNDLE in which case we enable it on our side anyway */
  2450. if((offer && bundle) || janus_force_bundle) {
  2451. janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE);
  2452. } else {
  2453. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE);
  2454. }
  2455. /* Note: in case this is not an OFFER, we don't know whether rtcp-mux is supported on the other side or not yet,
  2456. * unless Janus was configured to force rtcp-mux in which case we enable it on our side anyway */
  2457. if((offer && rtcpmux) || janus_force_rtcpmux) {
  2458. janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX);
  2459. } else {
  2460. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX);
  2461. }
  2462. /* Note: in case this is not an OFFER, we don't know whether ICE trickling is supported on the other side or not yet */
  2463. if(offer && trickle) {
  2464. janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE);
  2465. } else {
  2466. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE);
  2467. }
  2468. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES);
  2469. janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE_SYNCED);
  2470.  
  2471. handle->icectx = g_main_context_new();
  2472. handle->iceloop = g_main_loop_new(handle->icectx, FALSE);
  2473. GError *error = NULL;
  2474. handle->icethread = g_thread_try_new("ice thread", &janus_ice_thread, handle, &error);
  2475. if(error != NULL) {
  2476. /* FIXME We should clear some resources... */
  2477. 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 : "??");
  2478. return -1;
  2479. }
  2480. handle->queued_packets = g_async_queue_new();
  2481. /* We wait for ICE to succeed before creating the related thread */
  2482. handle->send_thread = NULL;
  2483. /* Note: NICE_COMPATIBILITY_RFC5245 is only available in more recent versions of libnice */
  2484. handle->controlling = janus_ice_lite_enabled ? FALSE : !offer;
  2485. JANUS_LOG(LOG_INFO, "[%"SCNu64"] Creating ICE agent (ICE %s mode, %s)\n", handle->handle_id,
  2486. janus_ice_lite_enabled ? "Lite" : "Full", handle->controlling ? "controlling" : "controlled");
  2487. g_atomic_int_set(&handle->send_thread_created, 0);
  2488. handle->agent = g_object_new(NICE_TYPE_AGENT,
  2489. "compatibility", NICE_COMPATIBILITY_DRAFT19,
  2490. "main-context", handle->icectx,
  2491. "reliable", FALSE,
  2492. "full-mode", janus_ice_lite_enabled ? FALSE : TRUE,
  2493. #ifdef HAVE_LIBNICE_TCP
  2494. "ice-udp", TRUE,
  2495. "ice-tcp", janus_ice_tcp_enabled ? TRUE : FALSE,
  2496. #endif
  2497. NULL);
  2498. handle->agent_created = janus_get_monotonic_time();
  2499. /* Any STUN server to use? */
  2500. if(janus_stun_server != NULL && janus_stun_port > 0) {
  2501. g_object_set(G_OBJECT(handle->agent),
  2502. "stun-server", janus_stun_server,
  2503. "stun-server-port", janus_stun_port,
  2504. NULL);
  2505. }
  2506. /* Any dynamic TURN credentials to retrieve via REST API? */
  2507. gboolean have_turnrest_credentials = FALSE;
  2508. #ifdef HAVE_LIBCURL
  2509. janus_turnrest_response *turnrest_credentials = janus_turnrest_request();
  2510. if(turnrest_credentials != NULL) {
  2511. have_turnrest_credentials = TRUE;
  2512. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Got credentials from the TURN REST API backend!\n", handle->handle_id);
  2513. JANUS_LOG(LOG_HUGE, " -- Username: %s\n", turnrest_credentials->username);
  2514. JANUS_LOG(LOG_HUGE, " -- Password: %s\n", turnrest_credentials->password);
  2515. JANUS_LOG(LOG_HUGE, " -- TTL: %"SCNu32"\n", turnrest_credentials->ttl);
  2516. JANUS_LOG(LOG_HUGE, " -- Servers: %d\n", g_list_length(turnrest_credentials->servers));
  2517. GList *server = turnrest_credentials->servers;
  2518. while(server != NULL) {
  2519. janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
  2520. JANUS_LOG(LOG_HUGE, " -- -- URI: %s:%"SCNu16" (%d)\n", instance->server, instance->port, instance->transport);
  2521. server = server->next;
  2522. }
  2523. }
  2524. #endif
  2525. g_object_set(G_OBJECT(handle->agent), "upnp", FALSE, NULL);
  2526. g_object_set(G_OBJECT(handle->agent), "controlling-mode", handle->controlling, NULL);
  2527. g_signal_connect (G_OBJECT (handle->agent), "candidate-gathering-done",
  2528. G_CALLBACK (janus_ice_cb_candidate_gathering_done), handle);
  2529. g_signal_connect (G_OBJECT (handle->agent), "component-state-changed",
  2530. G_CALLBACK (janus_ice_cb_component_state_changed), handle);
  2531. #ifndef HAVE_LIBNICE_TCP
  2532. g_signal_connect (G_OBJECT (handle->agent), "new-selected-pair",
  2533. #else
  2534. g_signal_connect (G_OBJECT (handle->agent), "new-selected-pair-full",
  2535. #endif
  2536. G_CALLBACK (janus_ice_cb_new_selected_pair), handle);
  2537. #ifndef HAVE_LIBNICE_TCP
  2538. g_signal_connect (G_OBJECT (handle->agent), "new-remote-candidate",
  2539. #else
  2540. g_signal_connect (G_OBJECT (handle->agent), "new-remote-candidate-full",
  2541. #endif
  2542. G_CALLBACK (janus_ice_cb_new_remote_candidate), handle);
  2543.  
  2544. /* Add all local addresses, except those in the ignore list */
  2545. struct ifaddrs *ifaddr, *ifa;
  2546. int family, s, n;
  2547. char host[NI_MAXHOST];
  2548. if(getifaddrs(&ifaddr) == -1) {
  2549. JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error getting list of interfaces...", handle->handle_id);
  2550. } else {
  2551. for(ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
  2552. if(ifa->ifa_addr == NULL)
  2553. continue;
  2554. /* Skip interfaces which are not up and running */
  2555. if (!((ifa->ifa_flags & IFF_UP) && (ifa->ifa_flags & IFF_RUNNING)))
  2556. continue;
  2557. /* Skip loopback interfaces */
  2558. if (ifa->ifa_flags & IFF_LOOPBACK)
  2559. continue;
  2560. family = ifa->ifa_addr->sa_family;
  2561. if(family != AF_INET && family != AF_INET6)
  2562. continue;
  2563. /* We only add IPv6 addresses if support for them has been explicitly enabled (still WIP, mostly) */
  2564. if(family == AF_INET6 && !janus_ipv6_enabled)
  2565. continue;
  2566. /* Check the interface name first, we can ignore that as well: enforce list would be checked later */
  2567. if(janus_ice_enforce_list == NULL && ifa->ifa_name != NULL && janus_ice_is_ignored(ifa->ifa_name))
  2568. continue;
  2569. s = getnameinfo(ifa->ifa_addr,
  2570. (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
  2571. host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
  2572. if(s != 0) {
  2573. JANUS_LOG(LOG_ERR, "[%"SCNu64"] getnameinfo() failed: %s\n", handle->handle_id, gai_strerror(s));
  2574. continue;
  2575. }
  2576. /* Skip 0.0.0.0, :: and local scoped addresses */
  2577. if(!strcmp(host, "0.0.0.0") || !strcmp(host, "::") || !strncmp(host, "fe80:", 5))
  2578. continue;
  2579. /* Check if this IP address is in the ignore/enforce list, now: the enforce list has the precedence */
  2580. if(janus_ice_enforce_list != NULL) {
  2581. if(ifa->ifa_name != NULL && !janus_ice_is_enforced(ifa->ifa_name) && !janus_ice_is_enforced(host))
  2582. continue;
  2583. } else {
  2584. if(janus_ice_is_ignored(host))
  2585. continue;
  2586. }
  2587. /* Ok, add interface to the ICE agent */
  2588. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Adding %s to the addresses to gather candidates for\n", handle->handle_id, host);
  2589. NiceAddress addr_local;
  2590. nice_address_init (&addr_local);
  2591. if(!nice_address_set_from_string (&addr_local, host)) {
  2592. JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping invalid address %s\n", handle->handle_id, host);
  2593. continue;
  2594. }
  2595. nice_agent_add_local_address (handle->agent, &addr_local);
  2596. }
  2597. freeifaddrs(ifaddr);
  2598. }
  2599.  
  2600. handle->cdone = 0;
  2601. handle->streams_num = 0;
  2602. handle->streams = g_hash_table_new(NULL, NULL);
  2603. if(audio) {
  2604. /* Add an audio stream */
  2605. handle->streams_num++;
  2606. handle->audio_id = nice_agent_add_stream (handle->agent, janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) ? 1 : 2);
  2607. janus_ice_stream *audio_stream = (janus_ice_stream *)g_malloc0(sizeof(janus_ice_stream));
  2608. if(audio_stream == NULL) {
  2609. JANUS_LOG(LOG_FATAL, "Memory error!\n");
  2610. return -1;
  2611. }
  2612. handle->audio_mid = NULL;
  2613. audio_stream->stream_id = handle->audio_id;
  2614. audio_stream->handle = handle;
  2615. audio_stream->cdone = 0;
  2616. audio_stream->payload_type = -1;
  2617. audio_stream->disabled = FALSE;
  2618. /* FIXME By default, if we're being called we're DTLS clients, but this may be changed by ICE... */
  2619. audio_stream->dtls_role = offer ? JANUS_DTLS_ROLE_CLIENT : JANUS_DTLS_ROLE_ACTPASS;
  2620. audio_stream->audio_ssrc = g_random_int(); /* FIXME Should we look for conflicts? */
  2621. audio_stream->audio_ssrc_peer = 0; /* FIXME Right now we don't know what this will be */
  2622. audio_stream->video_ssrc = 0;
  2623. if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE)) {
  2624. /* If we're bundling, this stream is going to be used for video as well */
  2625. audio_stream->video_ssrc = g_random_int(); /* FIXME Should we look for conflicts? */
  2626. }
  2627. audio_stream->video_ssrc_peer = 0; /* FIXME Right now we don't know what this will be */
  2628. audio_stream->video_ssrc_peer_rtx = 0; /* FIXME Right now we don't know what this will be */
  2629. audio_stream->audio_rtcp_ctx = g_malloc0(sizeof(rtcp_context));
  2630. audio_stream->audio_rtcp_ctx->tb = 48000; /* May change later */
  2631. audio_stream->video_rtcp_ctx = g_malloc0(sizeof(rtcp_context));
  2632. audio_stream->video_rtcp_ctx->tb = 90000;
  2633. janus_mutex_init(&audio_stream->mutex);
  2634. audio_stream->components = g_hash_table_new(NULL, NULL);
  2635. g_hash_table_insert(handle->streams, GUINT_TO_POINTER(handle->audio_id), audio_stream);
  2636. if(!have_turnrest_credentials) {
  2637. /* No TURN REST API server and credentials, any static ones? */
  2638. if(janus_turn_server != NULL) {
  2639. /* We need relay candidates as well */
  2640. gboolean ok = nice_agent_set_relay_info(handle->agent, handle->audio_id, 1,
  2641. janus_turn_server, janus_turn_port, janus_turn_user, janus_turn_pwd, janus_turn_type);
  2642. if(!ok) {
  2643. JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
  2644. janus_turn_server, janus_turn_port);
  2645. }
  2646. }
  2647. #ifdef HAVE_LIBCURL
  2648. } else {
  2649. /* We need relay candidates as well: add all those we got */
  2650. GList *server = turnrest_credentials->servers;
  2651. while(server != NULL) {
  2652. janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
  2653. gboolean ok = nice_agent_set_relay_info(handle->agent, handle->audio_id, 1,
  2654. instance->server, instance->port,
  2655. turnrest_credentials->username, turnrest_credentials->password,
  2656. instance->transport);
  2657. if(!ok) {
  2658. JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
  2659. instance->server, instance->port);
  2660. }
  2661. server = server->next;
  2662. }
  2663. #endif
  2664. }
  2665. handle->audio_stream = audio_stream;
  2666. janus_ice_component *audio_rtp = (janus_ice_component *)g_malloc0(sizeof(janus_ice_component));
  2667. if(audio_rtp == NULL) {
  2668. JANUS_LOG(LOG_FATAL, "Memory error!\n");
  2669. return -1;
  2670. }
  2671. audio_rtp->stream = audio_stream;
  2672. audio_rtp->stream_id = audio_stream->stream_id;
  2673. audio_rtp->component_id = 1;
  2674. audio_rtp->candidates = NULL;
  2675. audio_rtp->local_candidates = NULL;
  2676. audio_rtp->remote_candidates = NULL;
  2677. audio_rtp->selected_pair = NULL;
  2678. audio_rtp->process_started = FALSE;
  2679. audio_rtp->source = NULL;
  2680. audio_rtp->dtls = NULL;
  2681. audio_rtp->retransmit_buffer = NULL;
  2682. audio_rtp->retransmit_log_ts = 0;
  2683. audio_rtp->retransmit_recent_cnt = 0;
  2684. audio_rtp->nack_sent_log_ts = 0;
  2685. audio_rtp->nack_sent_recent_cnt = 0;
  2686. audio_rtp->last_seqs_audio = NULL;
  2687. audio_rtp->last_seqs_video = NULL;
  2688. audio_rtp->last_slowlink_time = 0;
  2689. audio_rtp->sl_nack_period_ts = 0;
  2690. audio_rtp->sl_nack_recent_cnt = 0;
  2691. janus_ice_stats_reset(&audio_rtp->in_stats);
  2692. janus_ice_stats_reset(&audio_rtp->out_stats);
  2693. janus_mutex_init(&audio_rtp->mutex);
  2694. g_hash_table_insert(audio_stream->components, GUINT_TO_POINTER(1), audio_rtp);
  2695. audio_stream->rtp_component = audio_rtp;
  2696. #ifdef HAVE_PORTRANGE
  2697. /* FIXME: libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails with an undefined reference! */
  2698. nice_agent_set_port_range(handle->agent, handle->audio_id, 1, rtp_range_min, rtp_range_max);
  2699. #endif
  2700. janus_ice_component *audio_rtcp = NULL;
  2701. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)) {
  2702. audio_rtcp = (janus_ice_component *)g_malloc0(sizeof(janus_ice_component));
  2703. if(audio_rtcp == NULL) {
  2704. JANUS_LOG(LOG_FATAL, "Memory error!\n");
  2705. return -1;
  2706. }
  2707. if(!have_turnrest_credentials) {
  2708. /* No TURN REST API server and credentials, any static ones? */
  2709. if(janus_turn_server != NULL) {
  2710. /* We need relay candidates as well */
  2711. gboolean ok = nice_agent_set_relay_info(handle->agent, handle->audio_id, 2,
  2712. janus_turn_server, janus_turn_port, janus_turn_user, janus_turn_pwd, janus_turn_type);
  2713. if(!ok) {
  2714. JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
  2715. janus_turn_server, janus_turn_port);
  2716. }
  2717. }
  2718. #ifdef HAVE_LIBCURL
  2719. } else {
  2720. /* We need relay candidates as well: add all those we got */
  2721. GList *server = turnrest_credentials->servers;
  2722. while(server != NULL) {
  2723. janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
  2724. gboolean ok = nice_agent_set_relay_info(handle->agent, handle->audio_id, 2,
  2725. instance->server, instance->port,
  2726. turnrest_credentials->username, turnrest_credentials->password,
  2727. instance->transport);
  2728. if(!ok) {
  2729. JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
  2730. instance->server, instance->port);
  2731. }
  2732. server = server->next;
  2733. }
  2734. #endif
  2735. }
  2736. audio_rtcp->stream = audio_stream;
  2737. audio_rtcp->stream_id = audio_stream->stream_id;
  2738. audio_rtcp->component_id = 2;
  2739. audio_rtcp->candidates = NULL;
  2740. audio_rtcp->local_candidates = NULL;
  2741. audio_rtcp->remote_candidates = NULL;
  2742. audio_rtcp->selected_pair = NULL;
  2743. audio_rtcp->process_started = FALSE;
  2744. audio_rtcp->source = NULL;
  2745. audio_rtcp->dtls = NULL;
  2746. audio_rtcp->retransmit_buffer = NULL;
  2747. audio_rtcp->retransmit_log_ts = 0;
  2748. audio_rtcp->retransmit_recent_cnt = 0;
  2749. audio_rtcp->last_slowlink_time = 0;
  2750. audio_rtcp->sl_nack_period_ts = 0;
  2751. audio_rtcp->sl_nack_recent_cnt = 0;
  2752. janus_ice_stats_reset(&audio_rtcp->in_stats);
  2753. janus_ice_stats_reset(&audio_rtcp->out_stats);
  2754. janus_mutex_init(&audio_rtcp->mutex);
  2755. g_hash_table_insert(audio_stream->components, GUINT_TO_POINTER(2), audio_rtcp);
  2756. audio_stream->rtcp_component = audio_rtcp;
  2757. #ifdef HAVE_PORTRANGE
  2758. /* FIXME: libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails with an undefined reference! */
  2759. nice_agent_set_port_range(handle->agent, handle->audio_id, 2, rtp_range_min, rtp_range_max);
  2760. #endif
  2761. }
  2762. nice_agent_gather_candidates(handle->agent, handle->audio_id);
  2763. nice_agent_attach_recv(handle->agent, handle->audio_id, 1, g_main_loop_get_context (handle->iceloop), janus_ice_cb_nice_recv, audio_rtp);
  2764. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) && audio_rtcp != NULL)
  2765. nice_agent_attach_recv(handle->agent, handle->audio_id, 2, g_main_loop_get_context (handle->iceloop), janus_ice_cb_nice_recv, audio_rtcp);
  2766. }
  2767. if(video && (!audio || !janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE))) {
  2768. /* Add a video stream */
  2769. handle->streams_num++;
  2770. handle->video_id = nice_agent_add_stream (handle->agent, janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) ? 1 : 2);
  2771. janus_ice_stream *video_stream = (janus_ice_stream *)g_malloc0(sizeof(janus_ice_stream));
  2772. if(video_stream == NULL) {
  2773. JANUS_LOG(LOG_FATAL, "Memory error!\n");
  2774. return -1;
  2775. }
  2776. handle->video_mid = NULL;
  2777. video_stream->handle = handle;
  2778. video_stream->stream_id = handle->video_id;
  2779. video_stream->cdone = 0;
  2780. video_stream->payload_type = -1;
  2781. video_stream->disabled = FALSE;
  2782. /* FIXME By default, if we're being called we're DTLS clients, but this may be changed by ICE... */
  2783. video_stream->dtls_role = offer ? JANUS_DTLS_ROLE_CLIENT : JANUS_DTLS_ROLE_ACTPASS;
  2784. video_stream->video_ssrc = g_random_int(); /* FIXME Should we look for conflicts? */
  2785. video_stream->video_ssrc_peer = 0; /* FIXME Right now we don't know what this will be */
  2786. video_stream->video_ssrc_peer_rtx = 0; /* FIXME Right now we don't know what this will be */
  2787. video_stream->audio_ssrc = 0;
  2788. video_stream->audio_ssrc_peer = 0;
  2789. video_stream->video_rtcp_ctx = g_malloc0(sizeof(rtcp_context));
  2790. video_stream->video_rtcp_ctx->tb = 90000;
  2791. video_stream->components = g_hash_table_new(NULL, NULL);
  2792. janus_mutex_init(&video_stream->mutex);
  2793. g_hash_table_insert(handle->streams, GUINT_TO_POINTER(handle->video_id), video_stream);
  2794. if(!have_turnrest_credentials) {
  2795. /* No TURN REST API server and credentials, any static ones? */
  2796. if(janus_turn_server != NULL) {
  2797. /* We need relay candidates as well */
  2798. gboolean ok = nice_agent_set_relay_info(handle->agent, handle->video_id, 1,
  2799. janus_turn_server, janus_turn_port, janus_turn_user, janus_turn_pwd, janus_turn_type);
  2800. if(!ok) {
  2801. JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
  2802. janus_turn_server, janus_turn_port);
  2803. }
  2804. }
  2805. #ifdef HAVE_LIBCURL
  2806. } else {
  2807. /* We need relay candidates as well: add all those we got */
  2808. GList *server = turnrest_credentials->servers;
  2809. while(server != NULL) {
  2810. janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
  2811. gboolean ok = nice_agent_set_relay_info(handle->agent, handle->video_id, 1,
  2812. instance->server, instance->port,
  2813. turnrest_credentials->username, turnrest_credentials->password,
  2814. instance->transport);
  2815. if(!ok) {
  2816. JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
  2817. instance->server, instance->port);
  2818. }
  2819. server = server->next;
  2820. }
  2821. #endif
  2822. }
  2823. handle->video_stream = video_stream;
  2824. janus_ice_component *video_rtp = (janus_ice_component *)g_malloc0(sizeof(janus_ice_component));
  2825. if(video_rtp == NULL) {
  2826. JANUS_LOG(LOG_FATAL, "Memory error!\n");
  2827. return -1;
  2828. }
  2829. video_rtp->stream = video_stream;
  2830. video_rtp->stream_id = video_stream->stream_id;
  2831. video_rtp->component_id = 1;
  2832. video_rtp->candidates = NULL;
  2833. video_rtp->local_candidates = NULL;
  2834. video_rtp->remote_candidates = NULL;
  2835. video_rtp->selected_pair = NULL;
  2836. video_rtp->process_started = FALSE;
  2837. video_rtp->source = NULL;
  2838. video_rtp->dtls = NULL;
  2839. video_rtp->retransmit_buffer = NULL;
  2840. video_rtp->retransmit_log_ts = 0;
  2841. video_rtp->retransmit_recent_cnt = 0;
  2842. video_rtp->nack_sent_log_ts = 0;
  2843. video_rtp->nack_sent_recent_cnt = 0;
  2844. video_rtp->last_seqs_audio = NULL;
  2845. video_rtp->last_seqs_video = NULL;
  2846. video_rtp->last_slowlink_time = 0;
  2847. video_rtp->sl_nack_period_ts = 0;
  2848. video_rtp->sl_nack_recent_cnt = 0;
  2849. janus_ice_stats_reset(&video_rtp->in_stats);
  2850. janus_ice_stats_reset(&video_rtp->out_stats);
  2851. janus_mutex_init(&video_rtp->mutex);
  2852. g_hash_table_insert(video_stream->components, GUINT_TO_POINTER(1), video_rtp);
  2853. video_stream->rtp_component = video_rtp;
  2854. #ifdef HAVE_PORTRANGE
  2855. /* FIXME: libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails with an undefined reference! */
  2856. nice_agent_set_port_range(handle->agent, handle->video_id, 1, rtp_range_min, rtp_range_max);
  2857. #endif
  2858. janus_ice_component *video_rtcp = NULL;
  2859. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX)) {
  2860. video_rtcp = (janus_ice_component *)g_malloc0(sizeof(janus_ice_component));
  2861. if(video_rtcp == NULL) {
  2862. JANUS_LOG(LOG_FATAL, "Memory error!\n");
  2863. return -1;
  2864. }
  2865. if(!have_turnrest_credentials) {
  2866. /* No TURN REST API server and credentials, any static ones? */
  2867. if(janus_turn_server != NULL) {
  2868. /* We need relay candidates as well */
  2869. gboolean ok = nice_agent_set_relay_info(handle->agent, handle->video_id, 2,
  2870. janus_turn_server, janus_turn_port, janus_turn_user, janus_turn_pwd, janus_turn_type);
  2871. if(!ok) {
  2872. JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
  2873. janus_turn_server, janus_turn_port);
  2874. }
  2875. }
  2876. #ifdef HAVE_LIBCURL
  2877. } else {
  2878. /* We need relay candidates as well: add all those we got */
  2879. GList *server = turnrest_credentials->servers;
  2880. while(server != NULL) {
  2881. janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
  2882. gboolean ok = nice_agent_set_relay_info(handle->agent, handle->video_id, 2,
  2883. instance->server, instance->port,
  2884. turnrest_credentials->username, turnrest_credentials->password,
  2885. instance->transport);
  2886. if(!ok) {
  2887. JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
  2888. instance->server, instance->port);
  2889. }
  2890. server = server->next;
  2891. }
  2892. #endif
  2893. }
  2894. video_rtcp->stream = video_stream;
  2895. video_rtcp->stream_id = video_stream->stream_id;
  2896. video_rtcp->component_id = 2;
  2897. video_rtcp->candidates = NULL;
  2898. video_rtcp->local_candidates = NULL;
  2899. video_rtcp->remote_candidates = NULL;
  2900. video_rtcp->selected_pair = NULL;
  2901. video_rtcp->process_started = FALSE;
  2902. video_rtcp->source = NULL;
  2903. video_rtcp->dtls = NULL;
  2904. video_rtcp->retransmit_buffer = NULL;
  2905. video_rtcp->retransmit_log_ts = 0;
  2906. video_rtcp->retransmit_recent_cnt = 0;
  2907. video_rtcp->last_slowlink_time = 0;
  2908. video_rtcp->sl_nack_period_ts = 0;
  2909. video_rtcp->sl_nack_recent_cnt = 0;
  2910. janus_ice_stats_reset(&video_rtcp->in_stats);
  2911. janus_ice_stats_reset(&video_rtcp->out_stats);
  2912. janus_mutex_init(&video_rtcp->mutex);
  2913. g_hash_table_insert(video_stream->components, GUINT_TO_POINTER(2), video_rtcp);
  2914. video_stream->rtcp_component = video_rtcp;
  2915. #ifdef HAVE_PORTRANGE
  2916. /* FIXME: libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails with an undefined reference! */
  2917. nice_agent_set_port_range(handle->agent, handle->video_id, 2, rtp_range_min, rtp_range_max);
  2918. #endif
  2919. }
  2920. nice_agent_gather_candidates(handle->agent, handle->video_id);
  2921. nice_agent_attach_recv(handle->agent, handle->video_id, 1, g_main_loop_get_context (handle->iceloop), janus_ice_cb_nice_recv, video_rtp);
  2922. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) && video_rtcp != NULL)
  2923. nice_agent_attach_recv(handle->agent, handle->video_id, 2, g_main_loop_get_context (handle->iceloop), janus_ice_cb_nice_recv, video_rtcp);
  2924. }
  2925. #ifndef HAVE_SCTP
  2926. handle->data_id = 0;
  2927. handle->data_stream = NULL;
  2928. #else
  2929. if(data && ((!audio && !video) || !janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE))) {
  2930. /* Add a SCTP/DataChannel stream */
  2931. handle->streams_num++;
  2932. handle->data_id = nice_agent_add_stream (handle->agent, 1);
  2933. janus_ice_stream *data_stream = (janus_ice_stream *)g_malloc0(sizeof(janus_ice_stream));
  2934. if(data_stream == NULL) {
  2935. JANUS_LOG(LOG_FATAL, "Memory error!\n");
  2936. return -1;
  2937. }
  2938. handle->data_mid = NULL;
  2939. if(!have_turnrest_credentials) {
  2940. /* No TURN REST API server and credentials, any static ones? */
  2941. if(janus_turn_server != NULL) {
  2942. /* We need relay candidates as well */
  2943. gboolean ok = nice_agent_set_relay_info(handle->agent, handle->data_id, 1,
  2944. janus_turn_server, janus_turn_port, janus_turn_user, janus_turn_pwd, janus_turn_type);
  2945. if(!ok) {
  2946. JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
  2947. janus_turn_server, janus_turn_port);
  2948. }
  2949. }
  2950. #ifdef HAVE_LIBCURL
  2951. } else {
  2952. /* We need relay candidates as well: add all those we got */
  2953. GList *server = turnrest_credentials->servers;
  2954. while(server != NULL) {
  2955. janus_turnrest_instance *instance = (janus_turnrest_instance *)server->data;
  2956. gboolean ok = nice_agent_set_relay_info(handle->agent, handle->data_id, 1,
  2957. instance->server, instance->port,
  2958. turnrest_credentials->username, turnrest_credentials->password,
  2959. instance->transport);
  2960. if(!ok) {
  2961. JANUS_LOG(LOG_WARN, "Could not set TURN server, is the address correct? (%s:%"SCNu16")\n",
  2962. instance->server, instance->port);
  2963. }
  2964. server = server->next;
  2965. }
  2966. #endif
  2967. }
  2968. data_stream->handle = handle;
  2969. data_stream->stream_id = handle->data_id;
  2970. data_stream->cdone = 0;
  2971. data_stream->payload_type = -1;
  2972. data_stream->disabled = FALSE;
  2973. /* FIXME By default, if we're being called we're DTLS clients, but this may be changed by ICE... */
  2974. data_stream->dtls_role = offer ? JANUS_DTLS_ROLE_CLIENT : JANUS_DTLS_ROLE_ACTPASS;
  2975. data_stream->components = g_hash_table_new(NULL, NULL);
  2976. janus_mutex_init(&data_stream->mutex);
  2977. g_hash_table_insert(handle->streams, GUINT_TO_POINTER(handle->data_id), data_stream);
  2978. handle->data_stream = data_stream;
  2979. janus_ice_component *data_component = (janus_ice_component *)g_malloc0(sizeof(janus_ice_component));
  2980. if(data_component == NULL) {
  2981. JANUS_LOG(LOG_FATAL, "Memory error!\n");
  2982. return -1;
  2983. }
  2984. data_component->stream = data_stream;
  2985. data_component->stream_id = data_component->stream_id;
  2986. data_component->component_id = 1;
  2987. data_component->candidates = NULL;
  2988. data_component->local_candidates = NULL;
  2989. data_component->remote_candidates = NULL;
  2990. data_component->selected_pair = NULL;
  2991. data_component->process_started = FALSE;
  2992. data_component->source = NULL;
  2993. data_component->dtls = NULL;
  2994. data_component->retransmit_buffer = NULL;
  2995. data_component->retransmit_log_ts = 0;
  2996. data_component->retransmit_recent_cnt = 0;
  2997. data_component->last_slowlink_time = 0;
  2998. data_component->sl_nack_period_ts = 0;
  2999. data_component->sl_nack_recent_cnt = 0;
  3000. janus_ice_stats_reset(&data_component->in_stats);
  3001. janus_ice_stats_reset(&data_component->out_stats);
  3002. janus_mutex_init(&data_component->mutex);
  3003. g_hash_table_insert(data_stream->components, GUINT_TO_POINTER(1), data_component);
  3004. data_stream->rtp_component = data_component; /* We use the component called 'RTP' for data */
  3005. #ifdef HAVE_PORTRANGE
  3006. /* FIXME: libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails with an undefined reference! */
  3007. nice_agent_set_port_range(handle->agent, handle->data_id, 1, rtp_range_min, rtp_range_max);
  3008. #endif
  3009. nice_agent_gather_candidates(handle->agent, handle->data_id);
  3010. nice_agent_attach_recv(handle->agent, handle->data_id, 1, g_main_loop_get_context (handle->iceloop), janus_ice_cb_nice_recv, data_component);
  3011. }
  3012. #endif
  3013. #ifdef HAVE_LIBCURL
  3014. if(turnrest_credentials != NULL) {
  3015. janus_turnrest_response_destroy(turnrest_credentials);
  3016. turnrest_credentials = NULL;
  3017. }
  3018. #endif
  3019. return 0;
  3020. }
  3021.  
  3022. void *janus_ice_send_thread(void *data) {
  3023. janus_ice_handle *handle = (janus_ice_handle *)data;
  3024. JANUS_LOG(LOG_VERB, "[%"SCNu64"] ICE send thread started...\n", handle->handle_id);
  3025. janus_ice_queued_packet *pkt = NULL;
  3026. gint64 before = janus_get_monotonic_time(),
  3027. audio_rtcp_last_rr = before, audio_rtcp_last_sr = before,
  3028. video_rtcp_last_rr = before, video_rtcp_last_sr = before,
  3029. last_nack_cleanup = before;
  3030. while(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT)) {
  3031. if(handle->queued_packets != NULL) {
  3032. pkt = g_async_queue_timeout_pop(handle->queued_packets, 500000);
  3033. } else {
  3034. g_usleep(100000);
  3035. }
  3036. /* First of all, let's see if everything's fine on the recv side */
  3037. gint64 now = janus_get_monotonic_time();
  3038. if(now-before >= G_USEC_PER_SEC) {
  3039. if(handle->audio_stream && handle->audio_stream->rtp_component) {
  3040. janus_ice_component *component = handle->audio_stream->rtp_component;
  3041. GList *lastitem = g_list_last(component->in_stats.audio_bytes_lastsec);
  3042. janus_ice_stats_item *last = lastitem ? ((janus_ice_stats_item *)lastitem->data) : NULL;
  3043. if(!component->in_stats.audio_notified_lastsec && last && now-last->when >= G_USEC_PER_SEC) {
  3044. /* Notify that we missed more than a second of audio! */
  3045. component->in_stats.audio_notified_lastsec = TRUE;
  3046. JANUS_LOG(LOG_WARN, "[%"SCNu64"] Didn't receive audio for more than a second...\n", handle->handle_id);
  3047. janus_ice_notify_media(handle, FALSE, FALSE);
  3048. }
  3049. if(!component->in_stats.video_notified_lastsec && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE)) {
  3050. lastitem = g_list_last(component->in_stats.video_bytes_lastsec);
  3051. last = lastitem ? ((janus_ice_stats_item *)lastitem->data) : NULL;
  3052. if(last && now-last->when >= G_USEC_PER_SEC) {
  3053. /* Notify that we missed more than a second of video! */
  3054. component->in_stats.video_notified_lastsec = TRUE;
  3055. JANUS_LOG(LOG_WARN, "[%"SCNu64"] Didn't receive video for more than a second...\n", handle->handle_id);
  3056. janus_ice_notify_media(handle, TRUE, FALSE);
  3057. }
  3058. }
  3059. }
  3060. if(handle->video_stream && handle->video_stream->rtp_component) {
  3061. janus_ice_component *component = handle->video_stream->rtp_component;
  3062. GList *lastitem = g_list_last(component->in_stats.video_bytes_lastsec);
  3063. janus_ice_stats_item *last = lastitem ? ((janus_ice_stats_item *)lastitem->data) : NULL;
  3064. if(!component->in_stats.video_notified_lastsec && last && now-last->when >= G_USEC_PER_SEC) {
  3065. /* Notify that we missed more than a second of video! */
  3066. component->in_stats.video_notified_lastsec = TRUE;
  3067. JANUS_LOG(LOG_WARN, "[%"SCNu64"] Didn't receive video for more than a second...\n", handle->handle_id);
  3068. janus_ice_notify_media(handle, TRUE, FALSE);
  3069. }
  3070. }
  3071. before = now;
  3072. }
  3073. /* Let's check if it's time to send a RTCP RR as well */
  3074. if(now-audio_rtcp_last_rr >= 5*G_USEC_PER_SEC) {
  3075. janus_ice_stream *stream = handle->audio_stream;
  3076. if(handle->audio_stream && stream->audio_rtcp_ctx && stream->audio_rtcp_ctx->rtp_recvd) {
  3077. /* Create a RR */
  3078. int rrlen = 32;
  3079. char rtcpbuf[32];
  3080. rtcp_rr *rr = (rtcp_rr *)&rtcpbuf;
  3081. rr->header.version = 2;
  3082. rr->header.type = RTCP_RR;
  3083. rr->header.rc = 1;
  3084. rr->header.length = htons((rrlen/4)-1);
  3085. janus_rtcp_report_block(stream->audio_rtcp_ctx, &rr->rb[0]);
  3086. /* Enqueue it, we'll send it later */
  3087. janus_ice_relay_rtcp(handle, 0, rtcpbuf, 32);
  3088. }
  3089. audio_rtcp_last_rr = now;
  3090. }
  3091. if(now-video_rtcp_last_rr >= 5*G_USEC_PER_SEC) {
  3092. 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);
  3093. if(stream) {
  3094. if(stream->video_rtcp_ctx && stream->video_rtcp_ctx->rtp_recvd) {
  3095. /* Create a RR */
  3096. int rrlen = 32;
  3097. char rtcpbuf[32];
  3098. rtcp_rr *rr = (rtcp_rr *)&rtcpbuf;
  3099. rr->header.version = 2;
  3100. rr->header.type = RTCP_RR;
  3101. rr->header.rc = 1;
  3102. rr->header.length = htons((rrlen/4)-1);
  3103. janus_rtcp_report_block(stream->video_rtcp_ctx, &rr->rb[0]);
  3104. /* Enqueue it, we'll send it later */
  3105. janus_ice_relay_rtcp(handle, 1, rtcpbuf, 32);
  3106. }
  3107. }
  3108. video_rtcp_last_rr = now;
  3109. }
  3110. /* Do the same with SR/SDES */
  3111. if(now-audio_rtcp_last_sr >= 500000) {
  3112. janus_ice_stream *stream = handle->audio_stream;
  3113. if(stream && stream->rtp_component && stream->rtp_component->out_stats.audio_packets > 0) {
  3114. /* Create a SR/SDES compound */
  3115. int srlen = 28;
  3116. int sdeslen = 20;
  3117. char rtcpbuf[srlen+sdeslen];
  3118. rtcp_sr *sr = (rtcp_sr *)&rtcpbuf;
  3119. sr->header.version = 2;
  3120. sr->header.type = RTCP_SR;
  3121. sr->header.rc = 0;
  3122. sr->header.length = htons((srlen/4)-1);
  3123. struct timeval tv;
  3124. gettimeofday(&tv, NULL);
  3125. uint32_t s = tv.tv_sec + 2208988800u;
  3126. uint32_t u = tv.tv_usec;
  3127. uint32_t f = (u << 12) + (u << 8) - ((u * 3650) >> 6);
  3128. sr->si.ntp_ts_msw = htonl(s);
  3129. sr->si.ntp_ts_lsw = htonl(f);
  3130. /* Compute an RTP timestamp coherent with the NTP one */
  3131. rtcp_context *rtcp_ctx = stream->audio_rtcp_ctx;
  3132. if(rtcp_ctx == NULL) {
  3133. sr->si.rtp_ts = htonl(stream->audio_last_ts); /* FIXME */
  3134. } else {
  3135. int64_t ntp = tv.tv_sec*G_USEC_PER_SEC + tv.tv_usec;
  3136. if(rtcp_ctx->fsr_ts == 0)
  3137. rtcp_ctx->fsr_ts = ntp;
  3138. uint32_t rtp_ts = ((ntp-rtcp_ctx->fsr_ts)/1000)*(rtcp_ctx->tb/1000);
  3139. sr->si.rtp_ts = htonl(rtp_ts);
  3140. }
  3141. sr->si.s_packets = htonl(stream->rtp_component->out_stats.audio_packets);
  3142. sr->si.s_octets = htonl(stream->rtp_component->out_stats.audio_bytes);
  3143. rtcp_sdes *sdes = (rtcp_sdes *)&rtcpbuf[28];
  3144. janus_rtcp_sdes((char *)sdes, sdeslen, "janusaudio", 10);
  3145. /* Enqueue it, we'll send it later */
  3146. janus_ice_relay_rtcp(handle, 0, rtcpbuf, srlen+sdeslen);
  3147. }
  3148. audio_rtcp_last_sr = now;
  3149. }
  3150. if(now-video_rtcp_last_sr >= 500000) {
  3151. 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);
  3152. if(stream && stream->rtp_component && stream->rtp_component->out_stats.video_packets > 0) {
  3153. /* Create a SR/SDES compound */
  3154. int srlen = 28;
  3155. int sdeslen = 20;
  3156. char rtcpbuf[srlen+sdeslen];
  3157. rtcp_sr *sr = (rtcp_sr *)&rtcpbuf;
  3158. sr->header.version = 2;
  3159. sr->header.type = RTCP_SR;
  3160. sr->header.rc = 0;
  3161. sr->header.length = htons((srlen/4)-1);
  3162. struct timeval tv;
  3163. gettimeofday(&tv, NULL);
  3164. uint32_t s = tv.tv_sec + 2208988800u;
  3165. uint32_t u = tv.tv_usec;
  3166. uint32_t f = (u << 12) + (u << 8) - ((u * 3650) >> 6);
  3167. sr->si.ntp_ts_msw = htonl(s);
  3168. sr->si.ntp_ts_lsw = htonl(f);
  3169. /* Compute an RTP timestamp coherent with the NTP one */
  3170. rtcp_context *rtcp_ctx = stream->video_rtcp_ctx;
  3171. if(rtcp_ctx == NULL) {
  3172. sr->si.rtp_ts = htonl(stream->video_last_ts); /* FIXME */
  3173. } else {
  3174. int64_t ntp = tv.tv_sec*G_USEC_PER_SEC + tv.tv_usec;
  3175. if(rtcp_ctx->fsr_ts == 0)
  3176. rtcp_ctx->fsr_ts = ntp;
  3177. uint32_t rtp_ts = ((ntp-rtcp_ctx->fsr_ts)/1000)*(rtcp_ctx->tb/1000);
  3178. sr->si.rtp_ts = htonl(rtp_ts);
  3179. }
  3180. sr->si.s_packets = htonl(stream->rtp_component->out_stats.video_packets);
  3181. sr->si.s_octets = htonl(stream->rtp_component->out_stats.video_bytes);
  3182. rtcp_sdes *sdes = (rtcp_sdes *)&rtcpbuf[28];
  3183. janus_rtcp_sdes((char *)sdes, sdeslen, "janusvideo", 10);
  3184. /* Enqueue it, we'll send it later */
  3185. janus_ice_relay_rtcp(handle, 1, rtcpbuf, srlen+sdeslen);
  3186. }
  3187. video_rtcp_last_sr = now;
  3188. }
  3189. /* Should we clean up old NACK buffers? (we check each 1/4 of the max_nack_queue time) */
  3190. if(max_nack_queue > 0 && (now-last_nack_cleanup >= (max_nack_queue*250))) {
  3191. /* Check if we do for both streams */
  3192. janus_cleanup_nack_buffer(now, handle->audio_stream);
  3193. janus_cleanup_nack_buffer(now, handle->video_stream);
  3194. last_nack_cleanup = now;
  3195. }
  3196.  
  3197. /* Now let's get on with the packets */
  3198. if(pkt == NULL) {
  3199. continue;
  3200. }
  3201. if(pkt == &janus_ice_dtls_alert) {
  3202. /* The session is over, send an alert on all streams and components */
  3203. if(handle->streams != NULL) {
  3204. if(handle->audio_stream) {
  3205. janus_ice_stream *stream = handle->audio_stream;
  3206. if(stream->rtp_component)
  3207. janus_dtls_srtp_send_alert(stream->rtp_component->dtls);
  3208. if(stream->rtcp_component)
  3209. janus_dtls_srtp_send_alert(stream->rtcp_component->dtls);
  3210. }
  3211. if(handle->video_stream) {
  3212. janus_ice_stream *stream = handle->video_stream;
  3213. if(stream->rtp_component)
  3214. janus_dtls_srtp_send_alert(stream->rtp_component->dtls);
  3215. if(stream->rtcp_component)
  3216. janus_dtls_srtp_send_alert(stream->rtcp_component->dtls);
  3217. }
  3218. if(handle->data_stream) {
  3219. janus_ice_stream *stream = handle->data_stream;
  3220. if(stream->rtp_component)
  3221. janus_dtls_srtp_send_alert(stream->rtp_component->dtls);
  3222. if(stream->rtcp_component)
  3223. janus_dtls_srtp_send_alert(stream->rtcp_component->dtls);
  3224. }
  3225. }
  3226. continue;
  3227. }
  3228. if(pkt->data == NULL) {
  3229. g_free(pkt);
  3230. pkt = NULL;
  3231. continue;
  3232. }
  3233. if(pkt->control) {
  3234. /* RTCP */
  3235. int video = (pkt->type == JANUS_ICE_PACKET_VIDEO);
  3236. 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);
  3237. if(!stream) {
  3238. g_free(pkt->data);
  3239. pkt->data = NULL;
  3240. g_free(pkt);
  3241. pkt = NULL;
  3242. continue;
  3243. }
  3244. janus_ice_component *component = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) ? stream->rtp_component : stream->rtcp_component;
  3245. if(!component) {
  3246. g_free(pkt->data);
  3247. pkt->data = NULL;
  3248. g_free(pkt);
  3249. pkt = NULL;
  3250. continue;
  3251. }
  3252. if(!stream->cdone) {
  3253. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !stream->noerrorlog) {
  3254. JANUS_LOG(LOG_ERR, "[%"SCNu64"] %s candidates not gathered yet for stream??\n", handle->handle_id, video ? "video" : "audio");
  3255. stream->noerrorlog = 1; /* Don't flood with the same error all over again */
  3256. }
  3257. g_free(pkt->data);
  3258. pkt->data = NULL;
  3259. g_free(pkt);
  3260. pkt = NULL;
  3261. continue;
  3262. }
  3263. stream->noerrorlog = 0;
  3264. if(!component->dtls || !component->dtls->srtp_valid || !component->dtls->srtp_out) {
  3265. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !component->noerrorlog) {
  3266. 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);
  3267. component->noerrorlog = 1; /* Don't flood with the same error all over again */
  3268. }
  3269. g_free(pkt->data);
  3270. pkt->data = NULL;
  3271. g_free(pkt);
  3272. pkt = NULL;
  3273. continue;
  3274. }
  3275. component->noerrorlog = 0;
  3276. if(pkt->encrypted) {
  3277. /* Already SRTCP */
  3278. int sent = nice_agent_send(handle->agent, stream->stream_id, component->component_id, pkt->length, (const gchar *)pkt->data);
  3279. if(sent < pkt->length) {
  3280. JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... only sent %d bytes? (was %d)\n", handle->handle_id, sent, pkt->length);
  3281. }
  3282. } else {
  3283. /* Check if there's anything we need to do before sending */
  3284. uint64_t bitrate = janus_rtcp_get_remb(pkt->data, pkt->length);
  3285. if(bitrate > 0) {
  3286. /* There's a REMB, prepend a RR as it won't work otherwise */
  3287. int rrlen = 32;
  3288. char *rtcpbuf = g_malloc0(rrlen+pkt->length);
  3289. rtcp_rr *rr = (rtcp_rr *)rtcpbuf;
  3290. rr->header.version = 2;
  3291. rr->header.type = RTCP_RR;
  3292. rr->header.rc = 1;
  3293. rr->header.length = htons((rrlen/4)-1);
  3294. 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);
  3295. if(stream && stream->video_rtcp_ctx && stream->video_rtcp_ctx->rtp_recvd)
  3296. janus_rtcp_report_block(stream->video_rtcp_ctx, &rr->rb[0]);
  3297. /* Append REMB */
  3298. memcpy(rtcpbuf+rrlen, pkt->data, pkt->length);
  3299. /* Free old packet and update */
  3300. g_free(pkt->data);
  3301. pkt->data = rtcpbuf;
  3302. pkt->length = rrlen+pkt->length;
  3303. }
  3304. /* FIXME Copy in a buffer and fix SSRC */
  3305. char sbuf[JANUS_BUFSIZE];
  3306. memcpy(sbuf, pkt->data, pkt->length);
  3307. /* Fix all SSRCs! */
  3308. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_PLAN_B)) {
  3309. JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Fixing SSRCs (local %u, peer %u)\n", handle->handle_id,
  3310. video ? stream->video_ssrc : stream->audio_ssrc,
  3311. video ? stream->video_ssrc_peer : stream->audio_ssrc_peer);
  3312. janus_rtcp_fix_ssrc(NULL, sbuf, pkt->length, 1,
  3313. video ? stream->video_ssrc : stream->audio_ssrc,
  3314. video ? stream->video_ssrc_peer : stream->audio_ssrc_peer);
  3315. } else {
  3316. /* Plan B involved, we trust the plugin to set the right 'local' SSRC and we don't mess with it */
  3317. JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Fixing peer SSRC (Plan B, peer %u)\n", handle->handle_id,
  3318. video ? stream->video_ssrc_peer : stream->audio_ssrc_peer);
  3319. janus_rtcp_fix_ssrc(NULL, sbuf, pkt->length, 1, 0,
  3320. video ? stream->video_ssrc_peer : stream->audio_ssrc_peer);
  3321. }
  3322.  
  3323. int protected = pkt->length;
  3324. int res = 0;
  3325. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_PLAN_B)) {
  3326. res = srtp_protect_rtcp(component->dtls->srtp_out, sbuf, &protected);
  3327. } else {
  3328. /* We need to make sure different sources don't use the SRTP context at the same time */
  3329. janus_mutex_lock(&component->dtls->srtp_mutex);
  3330. res = srtp_protect_rtcp(component->dtls->srtp_out, sbuf, &protected);
  3331. janus_mutex_unlock(&component->dtls->srtp_mutex);
  3332. }
  3333. //~ JANUS_LOG(LOG_VERB, "[%"SCNu64"] ... SRTCP protect %s (len=%d-->%d)...\n", handle->handle_id, janus_get_srtp_error(res), pkt->length, protected);
  3334. if(res != err_status_ok) {
  3335. JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... SRTCP protect error... %s (len=%d-->%d)...\n", handle->handle_id, janus_get_srtp_error(res), pkt->length, protected);
  3336. } else {
  3337. /* Shoot! */
  3338. //~ JANUS_LOG(LOG_VERB, "[%"SCNu64"] ... Sending SRTCP packet (pt=%u, seq=%u, ts=%u)...\n", handle->handle_id,
  3339. //~ header->paytype, ntohs(header->seq_number), ntohl(header->timestamp));
  3340. int sent = nice_agent_send(handle->agent, stream->stream_id, component->component_id, protected, sbuf);
  3341. if(sent < protected) {
  3342. JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... only sent %d bytes? (was %d)\n", handle->handle_id, sent, protected);
  3343. }
  3344. }
  3345. }
  3346. g_free(pkt->data);
  3347. g_free(pkt);
  3348. continue;
  3349. } else {
  3350. /* RTP or data */
  3351. if(pkt->type == JANUS_ICE_PACKET_AUDIO || pkt->type == JANUS_ICE_PACKET_VIDEO) {
  3352. /* RTP */
  3353. int video = (pkt->type == JANUS_ICE_PACKET_VIDEO);
  3354. 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);
  3355. if(!stream) {
  3356. g_free(pkt->data);
  3357. pkt->data = NULL;
  3358. g_free(pkt);
  3359. pkt = NULL;
  3360. continue;
  3361. }
  3362. janus_ice_component *component = stream->rtp_component;
  3363. if(!component) {
  3364. g_free(pkt->data);
  3365. pkt->data = NULL;
  3366. g_free(pkt);
  3367. pkt = NULL;
  3368. continue;
  3369. }
  3370. if(!stream->cdone) {
  3371. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !stream->noerrorlog) {
  3372. JANUS_LOG(LOG_ERR, "[%"SCNu64"] %s candidates not gathered yet for stream??\n", handle->handle_id, video ? "video" : "audio");
  3373. stream->noerrorlog = 1; /* Don't flood with the same error all over again */
  3374. }
  3375. g_free(pkt->data);
  3376. pkt->data = NULL;
  3377. g_free(pkt);
  3378. pkt = NULL;
  3379. continue;
  3380. }
  3381. stream->noerrorlog = 0;
  3382. if(!component->dtls || !component->dtls->srtp_valid || !component->dtls->srtp_out) {
  3383. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !component->noerrorlog) {
  3384. JANUS_LOG(LOG_WARN, "[%"SCNu64"] %s stream component has no valid SRTP session (yet?)\n", handle->handle_id, video ? "video" : "audio");
  3385. component->noerrorlog = 1; /* Don't flood with the same error all over again */
  3386. }
  3387. g_free(pkt->data);
  3388. pkt->data = NULL;
  3389. g_free(pkt);
  3390. pkt = NULL;
  3391. continue;
  3392. }
  3393. component->noerrorlog = 0;
  3394. if(pkt->encrypted) {
  3395. /* Already RTP (probably a retransmission?) */
  3396. rtp_header *header = (rtp_header *)pkt->data;
  3397. JANUS_LOG(LOG_HUGE, "[%"SCNu64"] ... Retransmitting seq.nr %"SCNu16"\n\n", handle->handle_id, ntohs(header->seq_number));
  3398. int sent = nice_agent_send(handle->agent, stream->stream_id, component->component_id, pkt->length, (const gchar *)pkt->data);
  3399. if(sent < pkt->length) {
  3400. JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... only sent %d bytes? (was %d)\n", handle->handle_id, sent, pkt->length);
  3401. }
  3402. } else {
  3403. /* FIXME Copy in a buffer and fix SSRC */
  3404. char sbuf[JANUS_BUFSIZE];
  3405. memcpy(sbuf, pkt->data, pkt->length);
  3406. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_PLAN_B)) {
  3407. /* Overwrite SSRC */
  3408. rtp_header *header = (rtp_header *)sbuf;
  3409. header->ssrc = htonl(video ? stream->video_ssrc : stream->audio_ssrc);
  3410. }
  3411. int protected = pkt->length;
  3412. int res = srtp_protect(component->dtls->srtp_out, sbuf, &protected);
  3413. //~ JANUS_LOG(LOG_VERB, "[%"SCNu64"] ... SRTP protect %s (len=%d-->%d)...\n", handle->handle_id, janus_get_srtp_error(res), pkt->length, protected);
  3414. if(res != err_status_ok) {
  3415. rtp_header *header = (rtp_header *)sbuf;
  3416. guint32 timestamp = ntohl(header->timestamp);
  3417. guint16 seq = ntohs(header->seq_number);
  3418. 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);
  3419. } else {
  3420. /* Shoot! */
  3421. //~ JANUS_LOG(LOG_VERB, "[%"SCNu64"] ... Sending SRTP packet (pt=%u, ssrc=%u, seq=%u, ts=%u)...\n", handle->handle_id,
  3422. //~ header->type, ntohl(header->ssrc), ntohs(header->seq_number), ntohl(header->timestamp));
  3423. int sent = nice_agent_send(handle->agent, stream->stream_id, component->component_id, protected, sbuf);
  3424. if(sent < protected) {
  3425. JANUS_LOG(LOG_ERR, "[%"SCNu64"] ... only sent %d bytes? (was %d)\n", handle->handle_id, sent, protected);
  3426. }
  3427. /* Update stats */
  3428. if(sent > 0) {
  3429. /* Update the RTCP context as well */
  3430. rtp_header *header = (rtp_header *)sbuf;
  3431. guint32 timestamp = ntohl(header->timestamp);
  3432. if(pkt->type == JANUS_ICE_PACKET_AUDIO) {
  3433. component->out_stats.audio_packets++;
  3434. component->out_stats.audio_bytes += sent;
  3435. stream->audio_last_ts = timestamp;
  3436. /* Let's check if this was G.711: in case we may need to change the timestamp base */
  3437. rtcp_context *rtcp_ctx = video ? stream->video_rtcp_ctx : stream->audio_rtcp_ctx;
  3438. int pt = header->type;
  3439. if((pt == 0 || pt == 8) && (rtcp_ctx->tb == 48000))
  3440. rtcp_ctx->tb = 8000;
  3441. } else if(pkt->type == JANUS_ICE_PACKET_VIDEO) {
  3442. component->out_stats.video_packets++;
  3443. component->out_stats.video_bytes += sent;
  3444. stream->video_last_ts = timestamp;
  3445. }
  3446. }
  3447. if(max_nack_queue > 0) {
  3448. /* Save the packet for retransmissions that may be needed later */
  3449. janus_rtp_packet *p = (janus_rtp_packet *)g_malloc0(sizeof(janus_rtp_packet));
  3450. p->data = (char *)g_malloc0(protected);
  3451. memcpy(p->data, sbuf, protected);
  3452. p->length = protected;
  3453. p->created = janus_get_monotonic_time();
  3454. p->last_retransmit = 0;
  3455. janus_mutex_lock(&component->mutex);
  3456. component->retransmit_buffer = g_list_append(component->retransmit_buffer, p);
  3457. janus_mutex_unlock(&component->mutex);
  3458. }
  3459. }
  3460. }
  3461. } else {
  3462. /* Data */
  3463. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS)) {
  3464. g_free(pkt->data);
  3465. pkt->data = NULL;
  3466. g_free(pkt);
  3467. pkt = NULL;
  3468. continue;
  3469. }
  3470. #ifdef HAVE_SCTP
  3471. janus_ice_stream *stream = handle->data_stream ? handle->data_stream : (handle->audio_stream ? handle->audio_stream : handle->video_stream);
  3472. if(!stream) {
  3473. g_free(pkt->data);
  3474. pkt->data = NULL;
  3475. g_free(pkt);
  3476. pkt = NULL;
  3477. continue;
  3478. }
  3479. janus_ice_component *component = stream->rtp_component;
  3480. if(!component) {
  3481. g_free(pkt->data);
  3482. pkt->data = NULL;
  3483. g_free(pkt);
  3484. pkt = NULL;
  3485. continue;
  3486. }
  3487. if(!stream->cdone) {
  3488. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !stream->noerrorlog) {
  3489. JANUS_LOG(LOG_ERR, "[%"SCNu64"] SCTP candidates not gathered yet for stream??\n", handle->handle_id);
  3490. stream->noerrorlog = 1; /* Don't flood with the same error all over again */
  3491. }
  3492. g_free(pkt->data);
  3493. pkt->data = NULL;
  3494. g_free(pkt);
  3495. pkt = NULL;
  3496. continue;
  3497. }
  3498. stream->noerrorlog = 0;
  3499. if(!component->dtls) {
  3500. if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && !component->noerrorlog) {
  3501. JANUS_LOG(LOG_WARN, "[%"SCNu64"] SCTP stream component has no valid DTLS session (yet?)\n", handle->handle_id);
  3502. component->noerrorlog = 1; /* Don't flood with the same error all over again */
  3503. }
  3504. g_free(pkt->data);
  3505. pkt->data = NULL;
  3506. g_free(pkt);
  3507. pkt = NULL;
  3508. continue;
  3509. }
  3510. component->noerrorlog = 0;
  3511. janus_dtls_wrap_sctp_data(component->dtls, pkt->data, pkt->length);
  3512. #endif
  3513. }
  3514. g_free(pkt->data);
  3515. pkt->data = NULL;
  3516. g_free(pkt);
  3517. pkt = NULL;
  3518. continue;
  3519. }
  3520. }
  3521. JANUS_LOG(LOG_VERB, "[%"SCNu64"] ICE send thread leaving...\n", handle->handle_id);
  3522. g_thread_unref(g_thread_self());
  3523. return NULL;
  3524. }
  3525.  
  3526. void janus_ice_relay_rtp(janus_ice_handle *handle, int video, char *buf, int len) {
  3527. if(!handle || buf == NULL || len < 1)
  3528. return;
  3529. if((!video && !janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO))
  3530. || (video && !janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO)))
  3531. return;
  3532. /* Queue this packet */
  3533. janus_ice_queued_packet *pkt = (janus_ice_queued_packet *)g_malloc0(sizeof(janus_ice_queued_packet));
  3534. pkt->data = g_malloc0(len);
  3535. memcpy(pkt->data, buf, len);
  3536. pkt->length = len;
  3537. pkt->type = video ? JANUS_ICE_PACKET_VIDEO : JANUS_ICE_PACKET_AUDIO;
  3538. pkt->control = FALSE;
  3539. pkt->encrypted = FALSE;
  3540. if(handle->queued_packets != NULL)
  3541. g_async_queue_push(handle->queued_packets, pkt);
  3542. }
  3543.  
  3544. static void janus_ice_relay_rtcp_internal(janus_ice_handle *handle, int video, char *buf, int len, gboolean filter_rtcp) {
  3545. if(!handle || buf == NULL || len < 1)
  3546. return;
  3547. /* We use this internal method to check whether we need to filter RTCP (e.g., to make
  3548. * sure we don't just forward any SR/RR from peers/plugins, but use our own) or it has
  3549. * already been done, and so this is actually a packet added by the ICE send thread */
  3550. char *rtcp_buf = buf;
  3551. int rtcp_len = len;
  3552. if(filter_rtcp) {
  3553. /* FIXME Strip RR/SR/SDES/NACKs/etc. */
  3554. rtcp_buf = janus_rtcp_filter(buf, len, &rtcp_len);
  3555. if(rtcp_buf == NULL)
  3556. return;
  3557. }
  3558. if(rtcp_len < 1)
  3559. return;
  3560. /* Queue this packet */
  3561. janus_ice_queued_packet *pkt = (janus_ice_queued_packet *)g_malloc0(sizeof(janus_ice_queued_packet));
  3562. pkt->data = g_malloc0(len);
  3563. memcpy(pkt->data, rtcp_buf, rtcp_len);
  3564. pkt->length = rtcp_len;
  3565. pkt->type = video ? JANUS_ICE_PACKET_VIDEO : JANUS_ICE_PACKET_AUDIO;
  3566. pkt->control = TRUE;
  3567. pkt->encrypted = FALSE;
  3568. if(handle->queued_packets != NULL)
  3569. g_async_queue_push(handle->queued_packets, pkt);
  3570. if(rtcp_buf != buf) {
  3571. /* We filtered the original packet, deallocate it */
  3572. g_free(rtcp_buf);
  3573. }
  3574. }
  3575.  
  3576. void janus_ice_relay_rtcp(janus_ice_handle *handle, int video, char *buf, int len) {
  3577. janus_ice_relay_rtcp_internal(handle, video, buf, len, TRUE);
  3578. }
  3579.  
  3580. #ifdef HAVE_SCTP
  3581. void janus_ice_relay_data(janus_ice_handle *handle, char *buf, int len) {
  3582. if(!handle || buf == NULL || len < 1)
  3583. return;
  3584. /* Queue this packet */
  3585. janus_ice_queued_packet *pkt = (janus_ice_queued_packet *)g_malloc0(sizeof(janus_ice_queued_packet));
  3586. pkt->data = g_malloc0(len);
  3587. memcpy(pkt->data, buf, len);
  3588. pkt->length = len;
  3589. pkt->type = JANUS_ICE_PACKET_DATA;
  3590. pkt->control = FALSE;
  3591. pkt->encrypted = FALSE;
  3592. if(handle->queued_packets != NULL)
  3593. g_async_queue_push(handle->queued_packets, pkt);
  3594. }
  3595. #endif
  3596.  
  3597. void janus_ice_dtls_handshake_done(janus_ice_handle *handle, janus_ice_component *component) {
  3598. if(!handle || !component)
  3599. return;
  3600. JANUS_LOG(LOG_VERB, "[%"SCNu64"] The DTLS handshake for the component %d in stream %d has been completed\n",
  3601. handle->handle_id, component->component_id, component->stream_id);
  3602. /* Check if all components are ready */
  3603. janus_mutex_lock(&handle->mutex);
  3604. if(handle->audio_stream && !handle->audio_stream->disabled) {
  3605. if(handle->audio_stream->rtp_component && (!handle->audio_stream->rtp_component->dtls ||
  3606. !handle->audio_stream->rtp_component->dtls->srtp_valid)) {
  3607. /* Still waiting for this component to become ready */
  3608. janus_mutex_unlock(&handle->mutex);
  3609. return;
  3610. }
  3611. if(handle->audio_stream->rtcp_component && (!handle->audio_stream->rtcp_component->dtls ||
  3612. !handle->audio_stream->rtcp_component->dtls->srtp_valid)) {
  3613. /* Still waiting for this component to become ready */
  3614. janus_mutex_unlock(&handle->mutex);
  3615. return;
  3616. }
  3617. }
  3618. if(handle->video_stream && !handle->video_stream->disabled) {
  3619. if(handle->video_stream->rtp_component && (!handle->video_stream->rtp_component->dtls ||
  3620. !handle->video_stream->rtp_component->dtls->srtp_valid)) {
  3621. /* Still waiting for this component to become ready */
  3622. janus_mutex_unlock(&handle->mutex);
  3623. return;
  3624. }
  3625. if(handle->video_stream->rtcp_component && (!handle->video_stream->rtcp_component->dtls ||
  3626. !handle->video_stream->rtcp_component->dtls->srtp_valid)) {
  3627. /* Still waiting for this component to become ready */
  3628. janus_mutex_unlock(&handle->mutex);
  3629. return;
  3630. }
  3631. }
  3632. if(handle->data_stream && !handle->data_stream->disabled) {
  3633. if(handle->data_stream->rtp_component && (!handle->data_stream->rtp_component->dtls ||
  3634. !handle->data_stream->rtp_component->dtls->srtp_valid)) {
  3635. /* Still waiting for this component to become ready */
  3636. janus_mutex_unlock(&handle->mutex);
  3637. return;
  3638. }
  3639. }
  3640. if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY)) {
  3641. /* Already notified */
  3642. janus_mutex_unlock(&handle->mutex);
  3643. return;
  3644. }
  3645. janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_READY);
  3646. janus_mutex_unlock(&handle->mutex);
  3647. JANUS_LOG(LOG_INFO, "[%"SCNu64"] The DTLS handshake has been completed\n", handle->handle_id);
  3648. /* Notify the plugin that the WebRTC PeerConnection is ready to be used */
  3649. janus_plugin *plugin = (janus_plugin *)handle->app;
  3650. if(plugin != NULL) {
  3651. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Telling the plugin about it (%s)\n", handle->handle_id, plugin->get_name());
  3652. if(plugin && plugin->setup_media && janus_plugin_session_is_alive(handle->app_handle))
  3653. plugin->setup_media(handle->app_handle);
  3654. }
  3655. /* Also prepare JSON event to notify user/application */
  3656. janus_session *session = (janus_session *)handle->session;
  3657. if(session == NULL)
  3658. return;
  3659. json_t *event = json_object();
  3660. json_object_set_new(event, "janus", json_string("webrtcup"));
  3661. json_object_set_new(event, "session_id", json_integer(session->session_id));
  3662. json_object_set_new(event, "sender", json_integer(handle->handle_id));
  3663. /* Send the event */
  3664. JANUS_LOG(LOG_VERB, "[%"SCNu64"] Sending event to transport...\n", handle->handle_id);
  3665. janus_session_notify_event(session->session_id, event);
  3666. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement