1 /*! \file ice.h 2 * \author Lorenzo Miniero <lorenzo@meetecho.com> 3 * \copyright GNU General Public License v3 4 * \brief ICE/STUN/TURN processing (headers) 5 * \details Implementation (based on libnice) of the ICE process. The 6 * code handles the whole ICE process, from the gathering of candidates 7 * to the final setup of a virtual channel RTP and RTCP can be transported 8 * on. Incoming RTP and RTCP packets from peers are relayed to the associated 9 * plugins by means of the incoming_rtp and incoming_rtcp callbacks. Packets 10 * to be sent to peers are relayed by peers invoking the relay_rtp and 11 * relay_rtcp core callbacks instead. 12 * 13 * \ingroup protocols 14 * \ref protocols 15 */ 16 17 #ifndef JANUS_ICE_H 18 #define JANUS_ICE_H 19 20 #include <glib.h> 21 #include <agent.h> 22 23 #include "sdp.h" 24 #include "dtls.h" 25 #include "sctp.h" 26 #include "rtcp.h" 27 #include "text2pcap.h" 28 #include "utils.h" 29 #include "ip-utils.h" 30 #include "refcount.h" 31 #include "plugins/plugin.h" 32 33 34 /*! \brief ICE stuff initialization 35 * @param[in] ice_lite Whether the ICE Lite mode should be enabled or not 36 * @param[in] ice_tcp Whether ICE-TCP support should be enabled or not (only libnice >= 0.1.8, currently broken) 37 * @param[in] full_trickle Whether full-trickle must be used (instead of half-trickle) 38 * @param[in] ignore_mdns Whether mDNS candidates should be ignored, instead of resolved 39 * @param[in] ipv6 Whether IPv6 candidates must be negotiated or not 40 * @param[in] ipv6_linklocal Whether IPv6 link-local candidates should be gathered 41 * @param[in] rtp_min_port Minimum port to use for RTP/RTCP, if a range is to be used 42 * @param[in] rtp_max_port Maximum port to use for RTP/RTCP, if a range is to be used */ 43 void janus_ice_init(gboolean ice_lite, gboolean ice_tcp, gboolean full_trickle, gboolean ignore_mdns, 44 gboolean ipv6, gboolean ipv6_linklocal, uint16_t rtp_min_port, uint16_t rtp_max_port); 45 /*! \brief ICE stuff de-initialization */ 46 void janus_ice_deinit(void); 47 /*! \brief Method to check whether a STUN server is reachable 48 * @param[in] addr Address of the STUN server as a janus_network_address instance 49 * @param[in] port Port of the STUN server 50 * @param[in] local_port Local port to bind to (0 means random choice) 51 * @param[out] public_addr Public address returned by the STUN server as a janus_network_address instance 52 * @param[out] public_port Public port returned by the STUN server 53 * @returns 0 in case of success, a negative integer on errors */ 54 int janus_ice_test_stun_server(janus_network_address *addr, uint16_t port, uint16_t local_port, janus_network_address *public_addr, uint16_t *public_port); 55 /*! \brief Method to force Janus to use a STUN server when gathering candidates 56 * @param[in] stun_server STUN server address to use 57 * @param[in] stun_port STUN port to use 58 * @returns 0 in case of success, a negative integer on errors */ 59 int janus_ice_set_stun_server(gchar *stun_server, uint16_t stun_port); 60 /*! \brief Method to force Janus to use a TURN server when gathering candidates 61 * @param[in] turn_server TURN server address to use 62 * @param[in] turn_port TURN port to use 63 * @param[in] turn_type Relay type (udp, tcp or tls) 64 * @param[in] turn_user TURN username, if needed 65 * @param[in] turn_pwd TURN password, if needed 66 * @returns 0 in case of success, a negative integer on errors */ 67 int janus_ice_set_turn_server(gchar *turn_server, uint16_t turn_port, gchar *turn_type, gchar *turn_user, gchar *turn_pwd); 68 /*! \brief Method to force Janus to contact a TURN REST API server to get a TURN service to use when gathering candidates. 69 * The TURN REST API takes precedence over any static credential passed via janus_ice_set_turn_server 70 * @note Requires libcurl to be available, and a working TURN REST API backend (see turnrest.h) 71 * @param[in] api_server TURN REST API backend (NULL to disable the API) 72 * @param[in] api_key API key to use, if required 73 * @param[in] api_method HTTP method to use (POST by default) 74 * @param[in] api_timeout total timeout for HTTP method in seconds 75 * @returns 0 in case of success, a negative integer on errors */ 76 int janus_ice_set_turn_rest_api(gchar *api_server, gchar *api_key, gchar *api_method, uint api_timeout); 77 /*! \brief Method to get the STUN server IP address 78 * @returns The currently used STUN server IP address, if available, or NULL if not */ 79 char *janus_ice_get_stun_server(void); 80 /*! \brief Method to get the STUN server port 81 * @returns The currently used STUN server port, if available, or 0 if not */ 82 uint16_t janus_ice_get_stun_port(void); 83 /*! \brief Method to get the TURN server IP address 84 * @returns The currently used TURN server IP address, if available, or NULL if not */ 85 char *janus_ice_get_turn_server(void); 86 /*! \brief Method to get the TURN server port 87 * @returns The currently used TURN server port, if available, or 0 if not */ 88 uint16_t janus_ice_get_turn_port(void); 89 /*! \brief Method to get the specified TURN REST API backend, if any 90 * @returns The currently specified TURN REST API backend, if available, or NULL if not */ 91 char *janus_ice_get_turn_rest_api(void); 92 /*! \brief Method to enable applications to force Janus to use TURN */ 93 void janus_ice_allow_force_relay(void); 94 /*! \brief Method to check whether applications are allowed to force Janus to use TURN 95 * @returns TRUE if they're allowed, FALSE otherwise */ 96 gboolean janus_ice_is_force_relay_allowed(void); 97 /*! \brief Helper method to force Janus to overwrite all host candidates with the public IP 98 * @param[in] keep_private_host Whether we should keep the original private host as a separate candidate, or replace it */ 99 void janus_ice_enable_nat_1_1(gboolean keep_private_host); 100 /*! \brief Method to add an interface/IP to the enforce list for ICE (that is, only gather candidates from these and ignore the others) 101 * \note This method is especially useful to speed up the ICE gathering process on the server: in fact, 102 * if you know in advance which interface must be used (e.g., the main interface connected to the internet), 103 * adding it to the enforce list will prevent libnice from gathering candidates from other interfaces. 104 * If you're interested in excluding interfaces explicitly, instead, check janus_ice_ignore_interface. 105 * @param[in] ip Interface/IP to enforce (e.g., 192.168. or eth0) */ 106 void janus_ice_enforce_interface(const char *ip); 107 /*! \brief Method to check whether an interface is currently in the enforce list for ICE (that is, won't have candidates) 108 * @param[in] ip Interface/IP to check (e.g., 192.168.244.1 or eth1) 109 * @returns true if the interface/IP is in the enforce list, false otherwise */ 110 gboolean janus_ice_is_enforced(const char *ip); 111 /*! \brief Method to add an interface/IP to the ignore list for ICE (that is, don't gather candidates) 112 * \note This method is especially useful to speed up the ICE gathering process on the server: in fact, 113 * if you know in advance an interface is not going to be used (e.g., one of those created by VMware), 114 * adding it to the ignore list will prevent libnice from gathering a candidate for it. 115 * Unlike the enforce list, the ignore list also accepts IP addresses, partial or complete. 116 * If you're interested in only using specific interfaces, instead, check janus_ice_enforce_interface. 117 * @param[in] ip Interface/IP to ignore (e.g., 192.168. or eth1) */ 118 void janus_ice_ignore_interface(const char *ip); 119 /*! \brief Method to check whether an interface/IP is currently in the ignore list for ICE (that is, won't have candidates) 120 * @param[in] ip Interface/IP to check (e.g., 192.168.244.1 or eth1) 121 * @returns true if the interface/IP is in the ignore list, false otherwise */ 122 gboolean janus_ice_is_ignored(const char *ip); 123 /*! \brief Method to check whether ICE Lite mode is enabled or not (still WIP) 124 * @returns true if ICE-TCP support is enabled/supported, false otherwise */ 125 gboolean janus_ice_is_ice_lite_enabled(void); 126 /*! \brief Method to check whether ICE-TCP support is enabled/supported or not (still WIP) 127 * @returns true if ICE-TCP support is enabled/supported, false otherwise */ 128 gboolean janus_ice_is_ice_tcp_enabled(void); 129 /*! \brief Method to check whether full-trickle support is enabled or not 130 * @returns true if full-trickle support is enabled, false otherwise */ 131 gboolean janus_ice_is_full_trickle_enabled(void); 132 /*! \brief Method to check whether mDNS resolution is enabled or not 133 * @returns true if mDNS resolution is enabled, false otherwise */ 134 gboolean janus_ice_is_mdns_enabled(void); 135 /*! \brief Method to check whether IPv6 candidates are enabled/supported or not 136 * @returns true if IPv6 candidates are enabled/supported, false otherwise */ 137 gboolean janus_ice_is_ipv6_enabled(void); 138 /*! \brief Method to check whether IPv6 link-local candidates will be gathered or not 139 * \note This obviously only makes sense if IPv6 support is enabled in general 140 * @returns true if IPv6 link-local candidates will be gathered, false otherwise */ 141 gboolean janus_ice_is_ipv6_linklocal_enabled(void); 142 #ifdef HAVE_ICE_NOMINATION 143 /*! \brief Method to configure the ICE nomination mode (regular or aggressive) 144 * @param[in] nomination The ICE nomination mode (regular or aggressive) */ 145 void janus_ice_set_nomination_mode(const char *nomination); 146 /*! \brief Method to return a string description of the configured ICE nomination mode 147 * @returns "regular" or "aggressive" */ 148 const char *janus_ice_get_nomination_mode(void); 149 #endif 150 /*! \brief Method to enable/disable connectivity checks as keepalives for PeerConnections. 151 * \note The main rationale behind this setting is provided in the libnice documentation: 152 * https://libnice.freedesktop.org/libnice/NiceAgent.html#NiceAgent--keepalive-conncheck 153 * @param[in] enabled Whether the functionality should be enabled or disabled */ 154 void janus_ice_set_keepalive_conncheck_enabled(gboolean enabled); 155 /*! \brief Method to check whether connectivity checks will be used as keepalives 156 * @returns true if enabled, false (default) otherwise */ 157 gboolean janus_ice_is_keepalive_conncheck_enabled(void); 158 /*! \brief Method to modify the min NACK value (i.e., the minimum time window of packets per handle to store for retransmissions) 159 * @param[in] mnq The new min NACK value */ 160 void janus_set_min_nack_queue(uint16_t mnq); 161 /*! \brief Method to get the current min NACK value (i.e., the minimum time window of packets per handle to store for retransmissions) 162 * @returns The current min NACK value */ 163 uint16_t janus_get_min_nack_queue(void); 164 /*! \brief Method to enable/disable the NACK optimizations on outgoing keyframes: when 165 * enabled, the NACK buffer for a PeerConnection is cleaned any time Janus sends a 166 * keyframe, as any missing packet won't be needed since the keyframe will allow the 167 * media recipient to still restore a complete image anyway. Since this optimization 168 * seems to cause some issues in some edge cases, it's disabled by default. 169 * @param[in] optimize Whether the optimization should be enabled or disabled */ 170 void janus_set_nack_optimizations_enabled(gboolean optimize); 171 /*! \brief Method to check whether NACK optimizations on outgoing keyframes are enabled or not 172 * @returns optimize if optimizations are enabled, false otherwise */ 173 gboolean janus_is_nack_optimizations_enabled(void); 174 /*! \brief Method to modify the no-media event timer (i.e., the number of seconds where no media arrives before Janus notifies this) 175 * @param[in] timer The new timer value, in seconds */ 176 void janus_set_no_media_timer(uint timer); 177 /*! \brief Method to get the current no-media event timer (see above) 178 * @returns The current no-media event timer */ 179 uint janus_get_no_media_timer(void); 180 /*! \brief Method to modify the slowlink-threshold property (i.e., the number of lost packets per seconds that should trigger a slow-link event) 181 * @param[in] packets The new value, in lost packets per seconds */ 182 void janus_set_slowlink_threshold(uint packets); 183 /*! \brief Method to get the current slowlink-threshold value (see above) 184 * @returns The current slowlink-threshold value */ 185 uint janus_get_slowlink_threshold(void); 186 /*! \brief Method to modify the TWCC feedback period (i.e., how often TWCC feedback is sent back to media senders) 187 * @param[in] period The new period value, in milliseconds */ 188 void janus_set_twcc_period(uint period); 189 /*! \brief Method to get the current TWCC period (see above) 190 * @returns The current TWCC period */ 191 uint janus_get_twcc_period(void); 192 /*! \brief Method to modify the DSCP value to set, which is disabled by default 193 * @param[in] dscp The new DSCP value (0 to disable) */ 194 void janus_set_dscp(int dscp); 195 /*! \brief Method to get the current DSCP value (see above) 196 * @returns The current DSCP value (0 if disabled) */ 197 int janus_get_dscp(void); 198 /*! \brief Method to modify the event handler statistics period (i.e., the number of seconds that should pass before Janus notifies event handlers about media statistics for a PeerConnection) 199 * @param[in] period The new period value, in seconds */ 200 void janus_ice_set_event_stats_period(int period); 201 /*! \brief Method to get the current event handler statistics period (see above) 202 * @returns The current event handler stats period */ 203 int janus_ice_get_event_stats_period(void); 204 205 /*! \brief Method to define wether the media stats shall be dispatched in one event (true) or in dedicated single events (false - default) 206 * @param[in] combine_media_stats_to_one_event true to combine media statistics in on event or false to send dedicated events */ 207 void janus_ice_event_set_combine_media_stats(gboolean combine_media_stats_to_one_event); 208 /*! \brief Method to retrieve wether media statistic events shall be dispatched combined or in single events 209 * @returns true to combine events */ 210 gboolean janus_ice_event_get_combine_media_stats(void); 211 212 /*! \brief Method to check whether libnice debugging has been enabled (http://nice.freedesktop.org/libnice/libnice-Debug-messages.html) 213 * @returns True if libnice debugging is enabled, FALSE otherwise */ 214 gboolean janus_ice_is_ice_debugging_enabled(void); 215 /*! \brief Method to enable libnice debugging (http://nice.freedesktop.org/libnice/libnice-Debug-messages.html) */ 216 void janus_ice_debugging_enable(void); 217 /*! \brief Method to disable libnice debugging (the default) */ 218 void janus_ice_debugging_disable(void); 219 /*! \brief Method to enable opaque ID in Janus API responses/events */ 220 void janus_enable_opaqueid_in_api(void); 221 /*! \brief Method to check whether opaque ID have to be added to Janus API responses/events 222 * @returns TRUE if they need to be present, FALSE otherwise */ 223 gboolean janus_is_opaqueid_in_api_enabled(void); 224 225 226 /*! \brief Helper method to get a string representation of a libnice ICE state 227 * @param[in] state The libnice ICE state 228 * @returns A string representation of the libnice ICE state */ 229 const gchar *janus_get_ice_state_name(gint state); 230 231 232 /*! \brief Janus ICE handle/session */ 233 typedef struct janus_ice_handle janus_ice_handle; 234 /*! \brief Janus ICE stream */ 235 typedef struct janus_ice_stream janus_ice_stream; 236 /*! \brief Janus ICE component */ 237 typedef struct janus_ice_component janus_ice_component; 238 /*! \brief Helper to handle pending trickle candidates (e.g., when we're still waiting for an offer) */ 239 typedef struct janus_ice_trickle janus_ice_trickle; 240 241 #define JANUS_ICE_HANDLE_WEBRTC_PROCESSING_OFFER (1 << 0) 242 #define JANUS_ICE_HANDLE_WEBRTC_START (1 << 1) 243 #define JANUS_ICE_HANDLE_WEBRTC_READY (1 << 2) 244 #define JANUS_ICE_HANDLE_WEBRTC_STOP (1 << 3) 245 #define JANUS_ICE_HANDLE_WEBRTC_ALERT (1 << 4) 246 #define JANUS_ICE_HANDLE_WEBRTC_NEGOTIATED (1 << 5) 247 #define JANUS_ICE_HANDLE_WEBRTC_TRICKLE (1 << 7) 248 #define JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES (1 << 8) 249 #define JANUS_ICE_HANDLE_WEBRTC_TRICKLE_SYNCED (1 << 9) 250 #define JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS (1 << 10) 251 #define JANUS_ICE_HANDLE_WEBRTC_CLEANING (1 << 11) 252 #define JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO (1 << 12) 253 #define JANUS_ICE_HANDLE_WEBRTC_HAS_VIDEO (1 << 13) 254 #define JANUS_ICE_HANDLE_WEBRTC_GOT_OFFER (1 << 14) 255 #define JANUS_ICE_HANDLE_WEBRTC_GOT_ANSWER (1 << 15) 256 #define JANUS_ICE_HANDLE_WEBRTC_HAS_AGENT (1 << 16) 257 #define JANUS_ICE_HANDLE_WEBRTC_ICE_RESTART (1 << 17) 258 #define JANUS_ICE_HANDLE_WEBRTC_RESEND_TRICKLES (1 << 18) 259 #define JANUS_ICE_HANDLE_WEBRTC_RFC4588_RTX (1 << 19) 260 #define JANUS_ICE_HANDLE_WEBRTC_NEW_DATACHAN_SDP (1 << 20) 261 #define JANUS_ICE_HANDLE_WEBRTC_E2EE (1 << 21) 262 263 264 /*! \brief Janus media statistics 265 * \note To improve with more stuff */ 266 typedef struct janus_ice_stats_info { 267 /*! \brief Packets sent or received */ 268 guint32 packets; 269 /*! \brief Bytes sent or received */ 270 guint64 bytes; 271 /*! \brief Bytes sent or received in the last second */ 272 guint32 bytes_lastsec, bytes_lastsec_temp; 273 /*! \brief Time we last updated the last second counter */ 274 gint64 updated; 275 /*! \brief Whether or not we notified about lastsec issues already */ 276 gboolean notified_lastsec; 277 /*! \brief Number of NACKs sent or received */ 278 guint32 nacks; 279 } janus_ice_stats_info; 280 281 /*! \brief Janus media statistics container 282 * \note To improve with more stuff */ 283 typedef struct janus_ice_stats { 284 /*! \brief Audio info */ 285 janus_ice_stats_info audio; 286 /*! \brief Video info (considering we may be simulcasting) */ 287 janus_ice_stats_info video[3]; 288 /*! \brief Data info */ 289 janus_ice_stats_info data; 290 /*! \brief Last known count of lost audio packets (for slow_link) */ 291 guint sl_lost_count_audio; 292 /*! \brief Last known count of lost video packets (for slow_link) */ 293 guint sl_lost_count_video; 294 } janus_ice_stats; 295 296 /*! \brief Quick helper method to notify a WebRTC hangup through the Janus API 297 * @param handle The janus_ice_handle instance this event refers to 298 * @param reason A description of why this happened */ 299 void janus_ice_notify_hangup(janus_ice_handle *handle, const char *reason); 300 301 302 /*! \brief Quick helper method to check if a plugin session associated with a Janus handle is still valid 303 * @param plugin_session The janus_plugin_session instance to validate 304 * @returns true if the plugin session is valid, false otherwise */ 305 gboolean janus_plugin_session_is_alive(janus_plugin_session *plugin_session); 306 307 308 /*! \brief A helper struct for determining when to send NACKs */ 309 typedef struct janus_seq_info { 310 gint64 ts; 311 guint16 seq; 312 guint16 state; 313 struct janus_seq_info *next; 314 struct janus_seq_info *prev; 315 } janus_seq_info; 316 void janus_seq_list_free(janus_seq_info **head); 317 enum { 318 SEQ_MISSING, 319 SEQ_NACKED, 320 SEQ_GIVEUP, 321 SEQ_RECVED 322 }; 323 324 325 /*! \brief Janus ICE handle */ 326 struct janus_ice_handle { 327 /*! \brief Opaque pointer to the core/peer session */ 328 void *session; 329 /*! \brief Handle identifier, guaranteed to be non-zero */ 330 guint64 handle_id; 331 /*! \brief Opaque identifier, e.g., to provide inter-handle relationships to external tools */ 332 char *opaque_id; 333 /*! \brief Token that was used to attach the handle, if required */ 334 char *token; 335 /*! \brief Monotonic time of when the handle has been created */ 336 gint64 created; 337 /*! \brief Opaque application (plugin) pointer */ 338 void *app; 339 /*! \brief Opaque core/plugin session pointer */ 340 janus_plugin_session *app_handle; 341 /*! \brief Mask of WebRTC-related flags for this handle */ 342 janus_flags webrtc_flags; 343 /*! \brief Number of gathered candidates */ 344 gint cdone; 345 /*! \brief GLib context for the handle and libnice */ 346 GMainContext *mainctx; 347 /*! \brief GLib loop for the handle and libnice */ 348 GMainLoop *mainloop; 349 /*! \brief GLib thread for the handle and libnice */ 350 GThread *thread; 351 /*! \brief GLib sources for outgoing traffic, recurring RTCP, and stats (and optionally TWCC) */ 352 GSource *rtp_source, *rtcp_source, *stats_source, *twcc_source; 353 /*! \brief libnice ICE agent */ 354 NiceAgent *agent; 355 /*! \brief Monotonic time of when the ICE agent has been created */ 356 gint64 agent_created; 357 /*! \brief ICE role (controlling or controlled) */ 358 gboolean controlling; 359 /*! \brief Audio mid (media ID) */ 360 gchar *audio_mid; 361 /*! \brief Video mid (media ID) */ 362 gchar *video_mid; 363 /*! \brief Data channel mid (media ID) */ 364 gchar *data_mid; 365 /*! \brief Main mid (will be a pointer to one of the above) */ 366 gchar *stream_mid; 367 /*! \brief ICE Stream ID */ 368 guint stream_id; 369 /*! \brief ICE stream */ 370 janus_ice_stream *stream; 371 /*! \brief RTP profile set by caller (so that we can match it) */ 372 gchar *rtp_profile; 373 /*! \brief SDP generated locally (just for debugging purposes) */ 374 gchar *local_sdp; 375 /*! \brief SDP received by the peer (just for debugging purposes) */ 376 gchar *remote_sdp; 377 /*! \brief Reason this handle has been hung up*/ 378 const gchar *hangup_reason; 379 /*! \brief List of pending trickle candidates (those we received before getting the JSEP offer) */ 380 GList *pending_trickles; 381 /*! \brief Queue of remote candidates that still need to be processed */ 382 GAsyncQueue *queued_candidates; 383 /*! \brief Queue of events in the loop and outgoing packets to send */ 384 GAsyncQueue *queued_packets; 385 /*! \brief Count of the recent SRTP replay errors, in order to avoid spamming the logs */ 386 guint srtp_errors_count; 387 /*! \brief Count of the recent SRTP replay errors, in order to avoid spamming the logs */ 388 gint last_srtp_error, last_srtp_summary; 389 /*! \brief Count of how many seconds passed since the last stats passed to event handlers */ 390 gint last_event_stats; 391 /*! \brief Flag to decide whether or not packets need to be dumped to a text2pcap file */ 392 volatile gint dump_packets; 393 /*! \brief In case this session must be saved to text2pcap, the instance to dump packets to */ 394 janus_text2pcap *text2pcap; 395 /*! \brief Mutex to lock/unlock the ICE session */ 396 janus_mutex mutex; 397 /*! \brief Whether a close_pc was requested recently on the PeerConnection */ 398 volatile gint closepc; 399 /*! \brief Atomic flag to check if this instance has been destroyed */ 400 volatile gint destroyed; 401 /*! \brief Reference counter for this instance */ 402 janus_refcount ref; 403 }; 404 405 /*! \brief Janus ICE stream */ 406 struct janus_ice_stream { 407 /*! \brief Janus ICE handle this stream belongs to */ 408 janus_ice_handle *handle; 409 /*! \brief libnice ICE stream ID */ 410 guint stream_id; 411 /*! \brief Whether this stream is ready to be used */ 412 gint cdone:1; 413 /*! \brief Audio SSRC of the server for this stream */ 414 guint32 audio_ssrc; 415 /*! \brief Video SSRC of the server for this stream */ 416 guint32 video_ssrc; 417 /*! \brief Video retransmission SSRC of the peer for this stream */ 418 guint32 video_ssrc_rtx; 419 /*! \brief Audio SSRC of the peer for this stream */ 420 guint32 audio_ssrc_peer, audio_ssrc_peer_new, audio_ssrc_peer_orig; 421 /*! \brief Video SSRC(s) of the peer for this stream (may be simulcasting) */ 422 guint32 video_ssrc_peer[3], video_ssrc_peer_new[3], video_ssrc_peer_orig[3], video_ssrc_peer_temp; 423 /*! \brief Video retransmissions SSRC(s) of the peer for this stream */ 424 guint32 video_ssrc_peer_rtx[3], video_ssrc_peer_rtx_new[3], video_ssrc_peer_rtx_orig[3]; 425 /*! \brief Array of RTP Stream IDs (for Firefox simulcasting, if enabled) */ 426 char *rid[3]; 427 /*! \brief Whether the order of the rids in the SDP will be h-m-l (TRUE) or l-m-h (FALSE) */ 428 gboolean rids_hml; 429 /*! \brief Whether we should use the legacy simulcast syntax (a=simulcast:recv rid=..) or the proper one (a=simulcast:recv ..) */ 430 gboolean legacy_rid; 431 /*! \brief RTP switching context(s) in case of renegotiations (audio+video and/or simulcast) */ 432 janus_rtp_switching_context rtp_ctx[3]; 433 /*! \brief List of payload types we can expect for audio */ 434 GList *audio_payload_types; 435 /*! \brief List of payload types we can expect for video */ 436 GList *video_payload_types; 437 /*! \brief Mapping of rtx payload types to actual media-related packet types */ 438 GHashTable *rtx_payload_types; 439 /*! \brief Mapping of payload types to their clock rates, as advertised in the SDP */ 440 GHashTable *clock_rates; 441 /*! \brief RTP payload types of this stream */ 442 gint audio_payload_type, video_payload_type, video_rtx_payload_type; 443 /*! \brief Codecs used by this stream */ 444 char *audio_codec, *video_codec; 445 /*! \brief Pointer to function to check if a packet is a keyframe (depends on negotiated codec) */ 446 gboolean (* video_is_keyframe)(const char* buffer, int len); 447 /*! \brief Media direction */ 448 gboolean audio_send, audio_recv, video_send, video_recv; 449 /*! \brief RTCP context for the audio stream */ 450 janus_rtcp_context *audio_rtcp_ctx; 451 /*! \brief RTCP context(s) for the video stream (may be simulcasting) */ 452 janus_rtcp_context *video_rtcp_ctx[3]; 453 /*! \brief Latest REMB feedback we received */ 454 uint32_t remb_bitrate; 455 /*! \brief Size of the NACK queue (in ms), dynamically updated per the RTT */ 456 uint16_t nack_queue_ms; 457 /*! \brief Map(s) of the NACKed packets (to track retransmissions and avoid duplicates) */ 458 GHashTable *rtx_nacked[3]; 459 /*! \brief Map of the pending NACKed cleanup callback */ 460 GHashTable *pending_nacked_cleanup; 461 /*! \brief First received audio NTP timestamp */ 462 gint64 audio_first_ntp_ts; 463 /*! \brief First received audio RTP timestamp */ 464 guint32 audio_first_rtp_ts; 465 /*! \brief First received video NTP timestamp (for all simulcast video streams) */ 466 gint64 video_first_ntp_ts[3]; 467 /*! \brief First received video NTP RTP timestamp (for all simulcast video streams) */ 468 guint32 video_first_rtp_ts[3]; 469 /*! \brief Last sent audio NTP timestamp */ 470 gint64 audio_last_ntp_ts; 471 /*! \brief Last sent audio RTP timestamp */ 472 guint32 audio_last_rtp_ts; 473 /*! \brief Last sent video NTP timestamp */ 474 gint64 video_last_ntp_ts; 475 /*! \brief Last sent video RTP timestamp */ 476 guint32 video_last_rtp_ts; 477 /*! \brief SDES mid RTP extension ID */ 478 gint mid_ext_id; 479 /*! \brief RTP Stream extension ID, and the related rtx one */ 480 gint rid_ext_id, ridrtx_ext_id; 481 /*! \brief Audio levels extension ID */ 482 gint audiolevel_ext_id; 483 /*! \brief Video orientation extension ID */ 484 gint videoorientation_ext_id; 485 /*! \brief Absolute Send Time ext ID */ 486 gint abs_send_time_ext_id; 487 /*! \brief Whether we do transport wide cc for video */ 488 gboolean do_transport_wide_cc; 489 /*! \brief Transport wide cc rtp ext ID */ 490 gint transport_wide_cc_ext_id; 491 /*! \brief Last sent transport wide seq num */ 492 guint16 transport_wide_cc_out_seq_num; 493 /*! \brief Last received transport wide seq num */ 494 guint32 transport_wide_cc_last_seq_num; 495 /*! \brief Last transport wide seq num sent on feedback */ 496 guint32 transport_wide_cc_last_feedback_seq_num; 497 /*! \brief Transport wide cc transport seq num wrap cycles */ 498 guint16 transport_wide_cc_cycles; 499 /*! \brief Transport wide cc rtp ext ID */ 500 guint transport_wide_cc_feedback_count; 501 /*! \brief GLib list of transport wide cc stats in reverse received order */ 502 GSList *transport_wide_received_seq_nums; 503 /*! \brief DTLS role of the server for this stream */ 504 janus_dtls_role dtls_role; 505 /*! \brief Hashing algorhitm used by the peer for the DTLS certificate (e.g., "SHA-256") */ 506 gchar *remote_hashing; 507 /*! \brief Hashed fingerprint of the peer's certificate, as parsed in SDP */ 508 gchar *remote_fingerprint; 509 /*! \brief The ICE username for this stream */ 510 gchar *ruser; 511 /*! \brief The ICE password for this stream */ 512 gchar *rpass; 513 /*! \brief GLib hash table of components (IDs are the keys) */ 514 GHashTable *components; 515 /*! \brief ICE component */ 516 janus_ice_component *component; 517 /*! \brief Helper flag to avoid flooding the console with the same error all over again */ 518 gboolean noerrorlog; 519 /*! \brief Mutex to lock/unlock this stream */ 520 janus_mutex mutex; 521 /*! \brief Atomic flag to check if this instance has been destroyed */ 522 volatile gint destroyed; 523 /*! \brief Reference counter for this instance */ 524 janus_refcount ref; 525 }; 526 527 #define LAST_SEQS_MAX_LEN 160 528 /*! \brief Janus ICE component */ 529 struct janus_ice_component { 530 /*! \brief Janus ICE stream this component belongs to */ 531 janus_ice_stream *stream; 532 /*! \brief libnice ICE stream ID */ 533 guint stream_id; 534 /*! \brief libnice ICE component ID */ 535 guint component_id; 536 /*! \brief libnice ICE component state */ 537 guint state; 538 /*! \brief Monotonic time of when this component has successfully connected */ 539 gint64 component_connected; 540 /*! \brief GLib list of libnice remote candidates for this component */ 541 GSList *candidates; 542 /*! \brief GLib list of local candidates for this component (summary) */ 543 GSList *local_candidates; 544 /*! \brief GLib list of remote candidates for this component (summary) */ 545 GSList *remote_candidates; 546 /*! \brief String representation of the selected pair as notified by libnice (foundations) */ 547 gchar *selected_pair; 548 /*! \brief Whether the setup of remote candidates for this component has started or not */ 549 gboolean process_started; 550 /*! \brief Timer to check when we should consider ICE as failed */ 551 GSource *icestate_source; 552 /*! \brief Time of when we first detected an ICE failed (we'll need this for the timer above) */ 553 gint64 icefailed_detected; 554 /*! \brief Re-transmission timer for DTLS */ 555 GSource *dtlsrt_source; 556 /*! \brief DTLS-SRTP stack */ 557 janus_dtls_srtp *dtls; 558 /*! \brief Whether we should do NACKs (in or out) for audio */ 559 gboolean do_audio_nacks; 560 /*! \brief Whether we should do NACKs (in or out) for video */ 561 gboolean do_video_nacks; 562 /*! \brief List of previously sent janus_rtp_packet RTP packets, in case we receive NACKs */ 563 GQueue *audio_retransmit_buffer, *video_retransmit_buffer; 564 /*! \brief HashTable of retransmittable sequence numbers, in case we receive NACKs */ 565 GHashTable *audio_retransmit_seqs, *video_retransmit_seqs; 566 /*! \brief Current sequence number for the RFC4588 rtx SSRC session */ 567 guint16 rtx_seq_number; 568 /*! \brief Last time a log message about sending retransmits was printed */ 569 gint64 retransmit_log_ts; 570 /*! \brief Number of retransmitted packets since last log message */ 571 guint retransmit_recent_cnt; 572 /*! \brief Last time a log message about sending NACKs was printed */ 573 gint64 nack_sent_log_ts; 574 /*! \brief Number of NACKs sent since last log message */ 575 guint nack_sent_recent_cnt; 576 /*! \brief List of recently received audio sequence numbers (as a support to NACK generation) */ 577 janus_seq_info *last_seqs_audio; 578 /*! \brief List of recently received video sequence numbers (as a support to NACK generation, for each simulcast SSRC) */ 579 janus_seq_info *last_seqs_video[3]; 580 /*! \brief Stats for incoming data (audio/video/data) */ 581 janus_ice_stats in_stats; 582 /*! \brief Stats for outgoing data (audio/video/data) */ 583 janus_ice_stats out_stats; 584 /*! \brief Helper flag to avoid flooding the console with the same error all over again */ 585 gboolean noerrorlog; 586 /*! \brief Mutex to lock/unlock this component */ 587 janus_mutex mutex; 588 /*! \brief Atomic flag to check if this instance has been destroyed */ 589 volatile gint destroyed; 590 /*! \brief Reference counter for this instance */ 591 janus_refcount ref; 592 }; 593 594 /*! \brief Helper to handle pending trickle candidates (e.g., when we're still waiting for an offer) */ 595 struct janus_ice_trickle { 596 /*! \brief Janus ICE handle this trickle candidate belongs to */ 597 janus_ice_handle *handle; 598 /*! \brief Monotonic time of when this trickle candidate has been received */ 599 gint64 received; 600 /*! \brief Janus API transaction ID of the original trickle request */ 601 char *transaction; 602 /*! \brief JSON object of the trickle candidate(s) */ 603 json_t *candidate; 604 }; 605 606 /** @name Janus ICE trickle candidates methods 607 */ 608 ///@{ 609 /*! \brief Helper method to allocate a janus_ice_trickle instance 610 * @param[in] transaction The Janus API ID of the original trickle request 611 * @param[in] candidate The trickle candidate, as a Jansson object 612 * @returns a pointer to the new instance, if successful, NULL otherwise */ 613 janus_ice_trickle *janus_ice_trickle_new(const char *transaction, json_t *candidate); 614 /*! \brief Helper method to parse trickle candidates 615 * @param[in] handle The Janus ICE handle this candidate belongs to 616 * @param[in] candidate The trickle candidate to parse, as a Jansson object 617 * @param[in,out] error Error string describing the failure, if any 618 * @returns 0 in case of success, any code from apierror.h in case of failure */ 619 gint janus_ice_trickle_parse(janus_ice_handle *handle, json_t *candidate, const char **error); 620 /*! \brief Helper method to destroy a janus_ice_trickle instance 621 * @param[in] trickle The janus_ice_trickle instance to destroy */ 622 void janus_ice_trickle_destroy(janus_ice_trickle *trickle); 623 ///@} 624 625 626 /** @name Janus ICE handle methods 627 */ 628 ///@{ 629 /*! \brief Method to create a new Janus ICE handle 630 * @param[in] core_session The core/peer session this ICE handle will belong to 631 * @param[in] opaque_id The opaque identifier provided by the creator, if any (optional) 632 * @param[in] token The auth token provided by the creator, if any (optional) 633 * @returns The created Janus ICE handle if successful, NULL otherwise */ 634 janus_ice_handle *janus_ice_handle_create(void *core_session, const char *opaque_id, const char *token); 635 /*! \brief Method to attach a Janus ICE handle to a plugin 636 * \details This method is very important, as it allows plugins to send/receive media (RTP/RTCP) to/from a WebRTC peer. 637 * @param[in] core_session The core/peer session this ICE handle belongs to 638 * @param[in] handle The Janus ICE handle 639 * @param[in] plugin The plugin the ICE handle needs to be attached to 640 * @param[in] loop_index In case static event loops are used, an indication on which loop to use for this handle 641 * (-1 will let the core pick one; in case API selection is disabled in the settings, this value is ignored) 642 * @returns 0 in case of success, a negative integer otherwise */ 643 gint janus_ice_handle_attach_plugin(void *core_session, janus_ice_handle *handle, janus_plugin *plugin, int loop_index); 644 /*! \brief Method to destroy a Janus ICE handle 645 * @param[in] core_session The core/peer session this ICE handle belongs to 646 * @param[in] handle The Janus ICE handle to destroy 647 * @returns 0 in case of success, a negative integer otherwise */ 648 gint janus_ice_handle_destroy(void *core_session, janus_ice_handle *handle); 649 /*! \brief Method to only hangup (e.g., DTLS alert) the WebRTC PeerConnection allocated by a Janus ICE handle 650 * @param[in] handle The Janus ICE handle instance managing the WebRTC PeerConnection to hangup 651 * @param[in] reason A description of why this happened */ 652 void janus_ice_webrtc_hangup(janus_ice_handle *handle, const char *reason); 653 /*! \brief Method to only free resources related to a specific ICE stream allocated by a Janus ICE handle 654 * @param[in] stream The Janus ICE stream instance to free */ 655 void janus_ice_stream_destroy(janus_ice_stream *stream); 656 /*! \brief Method to only free resources related to a specific ICE component allocated by a Janus ICE handle 657 * @param[in] component The Janus ICE component instance to free */ 658 void janus_ice_component_destroy(janus_ice_component *component); 659 ///@} 660 661 662 /** @name Janus ICE media relaying callbacks 663 */ 664 ///@{ 665 /*! \brief Core RTP callback, called when a plugin has an RTP packet to send to a peer 666 * @param[in] handle The Janus ICE handle associated with the peer 667 * @param[in] packet The RTP packet to send */ 668 void janus_ice_relay_rtp(janus_ice_handle *handle, janus_plugin_rtp *packet); 669 /*! \brief Core RTCP callback, called when a plugin has an RTCP message to send to a peer 670 * @param[in] handle The Janus ICE handle associated with the peer 671 * @param[in] packet The RTCP message to send */ 672 void janus_ice_relay_rtcp(janus_ice_handle *handle, janus_plugin_rtcp *packet); 673 /*! \brief Core SCTP/DataChannel callback, called when a plugin has data to send to a peer 674 * @param[in] handle The Janus ICE handle associated with the peer 675 * @param[in] packet The message to send */ 676 void janus_ice_relay_data(janus_ice_handle *handle, janus_plugin_data *packet); 677 /*! \brief Helper core callback, called when a plugin wants to send a RTCP PLI to a peer 678 * @param[in] handle The Janus ICE handle associated with the peer */ 679 void janus_ice_send_pli(janus_ice_handle *handle); 680 /*! \brief Helper core callback, called when a plugin wants to send a RTCP REMB to a peer 681 * @param[in] handle The Janus ICE handle associated with the peer 682 * @param[in] bitrate The bitrate value to put in the REMB message */ 683 void janus_ice_send_remb(janus_ice_handle *handle, uint32_t bitrate); 684 /*! \brief Plugin SCTP/DataChannel callback, called by the SCTP stack when when there's data for a plugin 685 * @param[in] handle The Janus ICE handle associated with the peer 686 * @param[in] label The label of the data channel the message is from 687 * @param[in] protocol The protocol of the data channel to use 688 * @param[in] textdata Whether the buffer is text (domstring) or binary data 689 * @param[in] buffer The message data (buffer) 690 * @param[in] length The buffer length */ 691 void janus_ice_incoming_data(janus_ice_handle *handle, char *label, char *protocol, gboolean textdata, char *buffer, int length); 692 /*! \brief Core SCTP/DataChannel callback, called by the SCTP stack when when there's data to send. 693 * @param[in] handle The Janus ICE handle associated with the peer 694 * @param[in] buffer The message data (buffer) 695 * @param[in] length The buffer length */ 696 void janus_ice_relay_sctp(janus_ice_handle *handle, char *buffer, int length); 697 /*! \brief Plugin SCTP/DataChannel callback, called by the SCTP stack when data can be written 698 * @param[in] handle The Janus ICE handle associated with the peer */ 699 void janus_ice_notify_data_ready(janus_ice_handle *handle); 700 /*! \brief Core SDP callback, called by the SDP stack when a stream has been paused by a negotiation 701 * @param[in] handle The Janus ICE handle associated with the peer */ 702 void janus_ice_notify_media_stopped(janus_ice_handle *handle); 703 ///@} 704 705 706 /** @name Janus ICE handle helpers 707 */ 708 ///@{ 709 /*! \brief Method to locally set up the ICE candidates (initialization and gathering) 710 * @param[in] handle The Janus ICE handle this method refers to 711 * @param[in] offer Whether this is for an OFFER or an ANSWER 712 * @param[in] audio Whether audio is enabled 713 * @param[in] video Whether video is enabled 714 * @param[in] data Whether SCTP data channels are enabled 715 * @param[in] trickle Whether ICE trickling is supported or not 716 * @returns 0 in case of success, a negative integer otherwise */ 717 int janus_ice_setup_local(janus_ice_handle *handle, int offer, int audio, int video, int data, int trickle); 718 /*! \brief Method to add local candidates to a janus_sdp SDP object representation 719 * @param[in] handle The Janus ICE handle this method refers to 720 * @param[in] mline The Janus SDP m-line object to add candidates to 721 * @param[in] stream_id The stream ID of the candidate to add to the SDP 722 * @param[in] component_id The component ID of the candidate to add to the SDP */ 723 void janus_ice_candidates_to_sdp(janus_ice_handle *handle, janus_sdp_mline *mline, guint stream_id, guint component_id); 724 /*! \brief Method to queue a remote candidate for processing 725 * @param[in] handle The Janus ICE handle this method refers to 726 * @param[in] c The remote NiceCandidate to process */ 727 void janus_ice_add_remote_candidate(janus_ice_handle *handle, NiceCandidate *c); 728 /*! \brief Method to handle remote candidates and start the connectivity checks 729 * @param[in] handle The Janus ICE handle this method refers to 730 * @param[in] stream_id The stream ID of the candidate to add to the SDP 731 * @param[in] component_id The component ID of the candidate to add to the SDP */ 732 void janus_ice_setup_remote_candidates(janus_ice_handle *handle, guint stream_id, guint component_id); 733 /*! \brief Callback to be notified when the DTLS handshake for a specific component has been completed 734 * \details This method also decides when to notify attached plugins about the availability of a reliable PeerConnection 735 * @param[in] handle The Janus ICE handle this callback refers to 736 * @param[in] component The Janus ICE component that is now ready to be used */ 737 void janus_ice_dtls_handshake_done(janus_ice_handle *handle, janus_ice_component *component); 738 /*! \brief Method to restart ICE and the connectivity checks 739 * @param[in] handle The Janus ICE handle this method refers to */ 740 void janus_ice_restart(janus_ice_handle *handle); 741 /*! \brief Method to resend all the existing candidates via trickle (e.g., after an ICE restart) 742 * @param[in] handle The Janus ICE handle this method refers to */ 743 void janus_ice_resend_trickles(janus_ice_handle *handle); 744 ///@} 745 746 747 /*! \brief Method to configure the static event loops mechanism at startup 748 * @note Check the \c event_loops property in the \c janus.jcfg configuration 749 * for an explanation of this feature, and the possible impact on Janus and users 750 * @param[in] loops The number of static event loops to start (0 to disable the feature) 751 * @param[in] allow_api Whether allocation on a specific loop driven via API should be allowed or not (false by default) */ 752 void janus_ice_set_static_event_loops(int loops, gboolean allow_api); 753 /*! \brief Method to return the number of static event loops, if enabled 754 * @returns The number of static event loops, if configured, or 0 if the feature is disabled */ 755 int janus_ice_get_static_event_loops(void); 756 /*! \brief Method to check whether loop indication via API is allowed 757 * @returns true if allowed, false otherwise */ 758 gboolean janus_ice_is_loop_indication_allowed(void); 759 /*! \brief Method to stop all the static event loops, if enabled 760 * @note This will wait for the related threads to exit, and so may delay the shutdown process */ 761 void janus_ice_stop_static_event_loops(void); 762 763 #endif 764