From 794e89ab896d8b87d26c25b6089edec756230f24 Mon Sep 17 00:00:00 2001 From: Bender Date: Wed, 3 Feb 2021 20:12:02 +0300 Subject: [PATCH 01/63] janus.js (#2548) customizeSdp callback added to handleRemoteJsep to be able to mangle remote SDP if needed --- html/janus.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/html/janus.js b/html/janus.js index a3a30f58d7f..66ca06cd5bc 100644 --- a/html/janus.js +++ b/html/janus.js @@ -2566,6 +2566,7 @@ function Janus(gatewayCallbacks) { callbacks = callbacks || {}; callbacks.success = (typeof callbacks.success == "function") ? callbacks.success : Janus.noop; callbacks.error = (typeof callbacks.error == "function") ? callbacks.error : webrtcError; + callbacks.customizeSdp = (typeof callbacks.customizeSdp == "function") ? callbacks.customizeSdp : Janus.noop; var jsep = callbacks.jsep; var pluginHandle = pluginHandles[handleId]; if(!pluginHandle || !pluginHandle.webrtcStuff) { @@ -2580,6 +2581,7 @@ function Janus(gatewayCallbacks) { callbacks.error("No PeerConnection: if this is an answer, use createAnswer and not handleRemoteJsep"); return; } + callbacks.customizeSdp(jsep); config.pc.setRemoteDescription(jsep) .then(function() { Janus.log("Remote description accepted!"); From 62440c5e3faa902e081000bfccab22e9b078b5fc Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Thu, 4 Feb 2021 11:52:44 +0100 Subject: [PATCH 02/63] Fix parsing of SDP to find payload type matching profiles (fixes #2544) (#2549) --- sdp-utils.c | 104 +++++++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 50 deletions(-) diff --git a/sdp-utils.c b/sdp-utils.c index 80d646778ee..8518bb39619 100644 --- a/sdp-utils.c +++ b/sdp-utils.c @@ -700,64 +700,20 @@ int janus_sdp_get_codec_pt_full(janus_sdp *sdp, const char *codec, const char *p ml = ml->next; continue; } - /* Look in all rtpmap attributes */ + /* Look in all rtpmap attributes first */ GList *ma = m->attributes; int pt = -1; - gboolean check_profile = FALSE; - gboolean got_profile = FALSE; + GList *pts = NULL; while(ma) { janus_sdp_attribute *a = (janus_sdp_attribute *)ma->data; - if(profile != NULL && a->name != NULL && a->value != NULL && !strcasecmp(a->name, "fmtp")) { - if(vp9) { - char profile_id[20]; - g_snprintf(profile_id, sizeof(profile_id), "profile-id=%s", profile); - if(strstr(a->value, profile_id) != NULL) { - /* Found */ - JANUS_LOG(LOG_VERB, "VP9 profile %s found --> %d\n", profile, pt); - if(check_profile) { - return pt; - } else { - got_profile = TRUE; - } - } - } else if(h264 && strstr(a->value, "packetization-mode=0") == NULL) { - /* We only support packetization-mode=1, no matter the profile */ - char profile_level_id[30]; - char *profile_lower = g_ascii_strdown(profile, -1); - g_snprintf(profile_level_id, sizeof(profile_level_id), "profile-level-id=%s", profile_lower); - g_free(profile_lower); - if(strstr(a->value, profile_level_id) != NULL) { - /* Found */ - JANUS_LOG(LOG_VERB, "H.264 profile %s found --> %d\n", profile, pt); - if(check_profile) { - return pt; - } else { - got_profile = TRUE; - } - } - /* Not found, try converting the profile to upper case */ - char *profile_upper = g_ascii_strup(profile, -1); - g_snprintf(profile_level_id, sizeof(profile_level_id), "profile-level-id=%s", profile_upper); - g_free(profile_upper); - if(strstr(a->value, profile_level_id) != NULL) { - /* Found */ - JANUS_LOG(LOG_VERB, "H.264 profile %s found --> %d\n", profile, pt); - if(check_profile) { - return pt; - } else { - got_profile = TRUE; - } - } - } - } else if(a->name != NULL && a->value != NULL && !strcasecmp(a->name, "rtpmap")) { + if(a->name != NULL && a->value != NULL && !strcasecmp(a->name, "rtpmap")) { pt = atoi(a->value); - check_profile = FALSE; if(pt < 0) { JANUS_LOG(LOG_ERR, "Invalid payload type (%s)\n", a->value); } else if(strstr(a->value, format) || strstr(a->value, format2)) { - if(profile != NULL && !got_profile && (vp9 || h264)) { - /* Let's check the profile first */ - check_profile = TRUE; + if(profile != NULL && (vp9 || h264)) { + /* Let's keep track of this payload type */ + pts = g_list_append(pts, GINT_TO_POINTER(pt)); } else { /* Payload type for codec found */ return pt; @@ -766,6 +722,54 @@ int janus_sdp_get_codec_pt_full(janus_sdp *sdp, const char *codec, const char *p } ma = ma->next; } + if(profile != NULL) { + /* Now look for the profile in the fmtp attributes */ + ma = m->attributes; + while(ma) { + janus_sdp_attribute *a = (janus_sdp_attribute *)ma->data; + if(profile != NULL && a->name != NULL && a->value != NULL && !strcasecmp(a->name, "fmtp")) { + /* Does this match the payload types we're looking for? */ + pt = atoi(a->value); + if(g_list_find(pts, GINT_TO_POINTER(pt)) == NULL) { + /* Not what we're looking for */ + ma = ma->next; + continue; + } + if(vp9) { + char profile_id[20]; + g_snprintf(profile_id, sizeof(profile_id), "profile-id=%s", profile); + if(strstr(a->value, profile_id) != NULL) { + /* Found */ + JANUS_LOG(LOG_VERB, "VP9 profile %s found --> %d\n", profile, pt); + return pt; + } + } else if(h264 && strstr(a->value, "packetization-mode=0") == NULL) { + /* We only support packetization-mode=1, no matter the profile */ + char profile_level_id[30]; + char *profile_lower = g_ascii_strdown(profile, -1); + g_snprintf(profile_level_id, sizeof(profile_level_id), "profile-level-id=%s", profile_lower); + g_free(profile_lower); + if(strstr(a->value, profile_level_id) != NULL) { + /* Found */ + JANUS_LOG(LOG_VERB, "H.264 profile %s found --> %d\n", profile, pt); + return pt; + } + /* Not found, try converting the profile to upper case */ + char *profile_upper = g_ascii_strup(profile, -1); + g_snprintf(profile_level_id, sizeof(profile_level_id), "profile-level-id=%s", profile_upper); + g_free(profile_upper); + if(strstr(a->value, profile_level_id) != NULL) { + /* Found */ + JANUS_LOG(LOG_VERB, "H.264 profile %s found --> %d\n", profile, pt); + return pt; + } + } + } + ma = ma->next; + } + } + if(pts != NULL) + g_list_free(pts); ml = ml->next; } return -1; From 24a0eec87ba52b35824862ca1150904f48454f39 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Thu, 4 Feb 2021 11:53:36 +0100 Subject: [PATCH 03/63] Videoroom race condition fixes (see #2509) (#2539) * Fixed missing room references that could cause crashes during race conditions * Fixed rare race condition on publisher join --- plugins/janus_videoroom.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index 10b499d96ca..6a0976458fb 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -3581,7 +3581,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi g_hash_table_iter_init(&iter, videoroom->participants); while (g_hash_table_iter_next(&iter, NULL, &value)) { janus_videoroom_publisher *p = value; - if(p && p->session) { + if(p && p->session && p->room) { g_clear_pointer(&p->room, janus_videoroom_room_dereference); /* Notify the user we're going to destroy the room... */ int ret = gateway->push_event(p->session->handle, &janus_videoroom_plugin, NULL, destroyed, NULL); @@ -6088,9 +6088,19 @@ static void *janus_videoroom_handler(void *data) { } /* Done */ janus_mutex_lock(&session->mutex); + /* Make sure the session has not been destroyed in the meanwhile */ + if(g_atomic_int_get(&session->destroyed)) { + janus_mutex_unlock(&session->mutex); + janus_mutex_unlock(&publisher->room->mutex); + janus_refcount_decrease(&publisher->room->ref); + janus_videoroom_publisher_destroy(publisher); + JANUS_LOG(LOG_ERR, "Session destroyed, invalidating new publisher\n"); + error_code = JANUS_VIDEOROOM_ERROR_UNKNOWN_ERROR; + g_snprintf(error_cause, 512, "Session destroyed, invalidating new publisher"); + goto error; + } session->participant_type = janus_videoroom_p_type_publisher; session->participant = publisher; - janus_mutex_unlock(&session->mutex); /* Return a list of all available publishers (those with an SDP available, that is) */ json_t *list = json_array(), *attendees = NULL; if(publisher->room->notify_joining) @@ -6101,6 +6111,7 @@ static void *janus_videoroom_handler(void *data) { g_hash_table_insert(publisher->room->participants, string_ids ? (gpointer)g_strdup(publisher->user_id_str) : (gpointer)janus_uint64_dup(publisher->user_id), publisher); + janus_mutex_unlock(&session->mutex); g_hash_table_iter_init(&iter, publisher->room->participants); while (!g_atomic_int_get(&publisher->room->destroyed) && g_hash_table_iter_next(&iter, NULL, &value)) { janus_videoroom_publisher *p = value; @@ -7246,8 +7257,10 @@ static void *janus_videoroom_handler(void *data) { if(p != participant && p->sdp) count++; } + janus_refcount_increase(&videoroom->ref); janus_mutex_unlock(&videoroom->mutex); if(count == videoroom->max_publishers) { + janus_refcount_decrease(&videoroom->ref); participant->audio_active = FALSE; participant->video_active = FALSE; participant->data_active = FALSE; @@ -7257,6 +7270,7 @@ static void *janus_videoroom_handler(void *data) { goto error; } if(videoroom->require_e2ee && !e2ee && !participant->e2ee) { + janus_refcount_decrease(&videoroom->ref); participant->audio_active = FALSE; participant->video_active = FALSE; participant->data_active = FALSE; @@ -7273,6 +7287,7 @@ static void *janus_videoroom_handler(void *data) { char error_str[512]; janus_sdp *offer = janus_sdp_parse(msg_sdp, error_str, sizeof(error_str)); if(offer == NULL) { + janus_refcount_decrease(&videoroom->ref); json_decref(event); JANUS_LOG(LOG_ERR, "Error parsing offer: %s\n", error_str); error_code = JANUS_VIDEOROOM_ERROR_INVALID_SDP; @@ -7580,6 +7595,7 @@ static void *janus_videoroom_handler(void *data) { } s = s->next; } + janus_refcount_decrease(&videoroom->ref); janus_mutex_unlock(&participant->subscribers_mutex); json_decref(update); } From 7732127f71521d1f1b305fdcf1073b3602f15b6e Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 8 Feb 2021 10:37:41 +0100 Subject: [PATCH 04/63] Updated Changelog (0.10.10) --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1cf3461d23..5d7a161de7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to this project will be documented in this file. +## [v0.10.10] - 2021-02-06 + +- Reduced verbosity of a few LOG_WARN messages at startup +- Close libnice agent resources asynchronously when hanging up PeerConnections (thanks @fbellet!) [[PR-2492](#2492)] +- Fixed broken parsing of SDP when trying to match specific codec profiles [[PR-2549](#2549)] +- Added muting/moderation API to the VideoRoom plugin [[PR-2513](#2513)] +- Fixed a few race conditions in VideoRoom plugin that could lead to crashes [[PR-2539][#2539)] +- Send 480 instead of BYE when hanging up calls in early dialog in the SIP plugin (thanks @zayim!) [[PR-2521](#2521)] +- Added configurable media direction when putting calls on-hold in the SIP plugin [[PR-2525](#2525)] +- Fixed rare race condition in AudioBridge when using "changeroom" (thanks @JeckLabs!) [[PR-2535][#2535)] +- Fixed broken API secret management in HTTP long polls (thanks @remvst!) [[PR-2524](#2524)] +- Report failure if binding to a socket fails in WebSockets transport plugin (thanks @Symbiatch!) [[PR-2534](#2534)] +- Updated RabbitMQ logic in both transport and event handler (thanks @chriswiggins!) [[PR-2430](#2430)] +- Fixed segfault in WebSocket event handler when backend was unreachable +- Added TLS support to MQTT event handler (thanks @RSATom!) [[PR-2517](#2517)] +- Other smaller fixes and improvements (thanks to all who contributed pull requests and reported issues!) + ## [v0.10.9] - 2020-12-23 - Replaced Travis CI with GitHub Actions [[PR-2486](#2486)] From 664022be731b902511de3e16b40e2bf893d7c732 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 8 Feb 2021 10:41:38 +0100 Subject: [PATCH 05/63] Bumped to version 0.11.1 --- bower.json | 2 +- configure.ac | 6 +++--- docs/janus-doxygen.cfg | 2 +- janus.ggo | 2 +- postprocessing/janus-pp-rec.ggo | 2 +- postprocessing/pcap2mjr.ggo | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bower.json b/bower.json index 293e52abdf5..a0d7c5acba0 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "janus-gateway", - "version": "0.10.10", + "version": "0.11.1", "homepage": "https://github.com/meetecho/janus-gateway", "authors": [ "Lorenzo Miniero ", diff --git a/configure.ac b/configure.ac index c75c6b98de2..6e5cf542baa 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([Janus WebRTC Server],[0.10.10],[https://github.com/meetecho/janus-gateway],[janus-gateway],[https://janus.conf.meetecho.com]) +AC_INIT([Janus WebRTC Server],[0.11.1],[https://github.com/meetecho/janus-gateway],[janus-gateway],[https://janus.conf.meetecho.com]) AC_LANG(C) AC_CONFIG_AUX_DIR([.]) AC_CONFIG_MACRO_DIR([m4]) @@ -70,9 +70,9 @@ clang*) -Wunused-but-set-variable" esac -JANUS_VERSION=110 +JANUS_VERSION=111 AC_SUBST(JANUS_VERSION) -JANUS_VERSION_STRING="0.10.10" +JANUS_VERSION_STRING="0.11.1" AC_SUBST(JANUS_VERSION_STRING) case "$host_os" in diff --git a/docs/janus-doxygen.cfg b/docs/janus-doxygen.cfg index 55c6036de74..601adc97f2d 100644 --- a/docs/janus-doxygen.cfg +++ b/docs/janus-doxygen.cfg @@ -38,7 +38,7 @@ PROJECT_NAME = "Janus" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 0.10.10 +PROJECT_NUMBER = 0.11.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/janus.ggo b/janus.ggo index b668b08ef31..fa8b157b6ca 100644 --- a/janus.ggo +++ b/janus.ggo @@ -1,4 +1,4 @@ -#Janus 0.10.10 gengetopt file +#Janus 0.11.1 gengetopt file option "daemon" b "Launch Janus in background as a daemon" flag off option "pid-file" p "Open the specified PID file when starting Janus (default=none)" string typestr="path" optional option "disable-stdout" N "Disable stdout based logging" flag off diff --git a/postprocessing/janus-pp-rec.ggo b/postprocessing/janus-pp-rec.ggo index 074d9d77bef..4ebed2e3974 100644 --- a/postprocessing/janus-pp-rec.ggo +++ b/postprocessing/janus-pp-rec.ggo @@ -1,4 +1,4 @@ -#Janus-pp-rec 0.10.10 gengetopt file +#Janus-pp-rec 0.11.1 gengetopt file usage "janus-pp-rec [OPTIONS] source.mjr [destination.[opus|wav|webm|mp4|srt]]" option "json" j "Only print JSON header" flag off option "header" H "Only parse .mjr header" flag off diff --git a/postprocessing/pcap2mjr.ggo b/postprocessing/pcap2mjr.ggo index 67abdc616cc..cb39039016e 100644 --- a/postprocessing/pcap2mjr.ggo +++ b/postprocessing/pcap2mjr.ggo @@ -1,4 +1,4 @@ -#pcap2mjr 0.10.10 gengetopt file +#pcap2mjr 0.11.1 gengetopt file usage "pcap2mjr [OPTIONS] source.pcap destination.mjr" option "codec" c "Codec the recording will contain (e.g., opus, vp8, etc.)" string typestr="codec" required option "ssrc" s "SSRC of the packets in the pcap file to save" int typestr="ssrc" required From 09daec4b7adf5a9dd03e59d21b1160392771043f Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 8 Feb 2021 10:46:06 +0100 Subject: [PATCH 06/63] Renamed extern janus_callbacks variables in Lua and Duktape plugins (#2540) --- plugins/janus_duktape.c | 52 ++++++++++++++++++------------------ plugins/janus_duktape_data.h | 2 +- plugins/janus_lua.c | 52 ++++++++++++++++++------------------ plugins/janus_lua_data.h | 2 +- 4 files changed, 54 insertions(+), 54 deletions(-) diff --git a/plugins/janus_duktape.c b/plugins/janus_duktape.c index 9a5ba7813e5..497a68f9654 100644 --- a/plugins/janus_duktape.c +++ b/plugins/janus_duktape.c @@ -266,7 +266,7 @@ janus_plugin *create(void) { /* Useful stuff */ volatile gint duktape_initialized = 0, duktape_stopping = 0; -janus_callbacks *janus_core = NULL; +janus_callbacks *duktape_janus_core = NULL; static char *duktape_folder = NULL; /* Duktape stuff */ @@ -401,7 +401,7 @@ static void *janus_duktape_async_event_helper(void *data) { return NULL; if(asev->type == janus_duktape_async_event_type_pushevent) { /* Send the event */ - janus_core->push_event(asev->session->handle, &janus_duktape_plugin, asev->transaction, asev->event, asev->jsep); + duktape_janus_core->push_event(asev->session->handle, &janus_duktape_plugin, asev->transaction, asev->event, asev->jsep); } json_decref(asev->event); json_decref(asev->jsep); @@ -646,7 +646,7 @@ static duk_ret_t janus_duktape_method_pushevent(duk_context *ctx) { return 1; } /* No SDP, send the event now */ - int res = janus_core->push_event(session->handle, &janus_duktape_plugin, transaction, event, NULL); + int res = duktape_janus_core->push_event(session->handle, &janus_duktape_plugin, transaction, event, NULL); janus_refcount_decrease(&session->ref); json_decref(event); duk_push_int(ctx, res); @@ -669,7 +669,7 @@ static duk_ret_t janus_duktape_method_notifyevent(duk_context *ctx) { if(event_text == NULL) return duk_throw(ctx); /* Get the arguments from the provided context */ - if(!janus_core->events_is_enabled()) { + if(!duktape_janus_core->events_is_enabled()) { /* Event handlers are disabled in the core, ignoring */ duk_push_int(ctx, 0); return 1; @@ -688,7 +688,7 @@ static duk_ret_t janus_duktape_method_notifyevent(duk_context *ctx) { janus_refcount_increase(&session->ref); janus_mutex_unlock(&duktape_sessions_mutex); /* Notify the event */ - janus_core->notify_event(&janus_duktape_plugin, session ? session->handle : NULL, event); + duktape_janus_core->notify_event(&janus_duktape_plugin, session ? session->handle : NULL, event); if(session != NULL) janus_refcount_decrease(&session->ref); duk_push_int(ctx, 0); @@ -697,7 +697,7 @@ static duk_ret_t janus_duktape_method_notifyevent(duk_context *ctx) { static duk_ret_t janus_duktape_method_eventsisenabled(duk_context *ctx) { /* Return info on whether event handlers are enabled in the core or not */ - duk_push_int(ctx, janus_core->events_is_enabled()); + duk_push_int(ctx, duktape_janus_core->events_is_enabled()); return 1; } @@ -719,7 +719,7 @@ static duk_ret_t janus_duktape_method_closepc(duk_context *ctx) { janus_refcount_increase(&session->ref); janus_mutex_unlock(&duktape_sessions_mutex); /* Close the PeerConnection */ - janus_core->close_pc(session->handle); + duktape_janus_core->close_pc(session->handle); duk_push_int(ctx, 0); return 1; } @@ -742,7 +742,7 @@ static duk_ret_t janus_duktape_method_endsession(duk_context *ctx) { janus_refcount_increase(&session->ref); janus_mutex_unlock(&duktape_sessions_mutex); /* Close the plugin handle */ - janus_core->end_session(session->handle); + duktape_janus_core->end_session(session->handle); duk_push_int(ctx, 0); return 1; } @@ -936,7 +936,7 @@ static duk_ret_t janus_duktape_method_setbitrate(duk_context *ctx) { /* Send a REMB right away too, if the PeerConnection is up */ if(g_atomic_int_get(&session->started)) { /* No limit ~= 10000000 */ - janus_core->send_remb(session->handle, session->bitrate ? session->bitrate : 10000000); + duktape_janus_core->send_remb(session->handle, session->bitrate ? session->bitrate : 10000000); } /* Done */ janus_refcount_decrease(&session->ref); @@ -1055,7 +1055,7 @@ static duk_ret_t janus_duktape_method_sendpli(duk_context *ctx) { /* Send a PLI */ session->pli_latest = janus_get_monotonic_time(); JANUS_LOG(LOG_HUGE, "Sending PLI to session %"SCNu32"\n", session->id); - janus_core->send_pli(session->handle); + duktape_janus_core->send_pli(session->handle); /* Done */ janus_refcount_decrease(&session->ref); duk_push_int(ctx, 0); @@ -1104,7 +1104,7 @@ static duk_ret_t janus_duktape_method_relayrtp(duk_context *ctx) { /* Send the RTP packet */ janus_plugin_rtp rtp = { .video = is_video, .buffer = (char *)payload, .length = len }; janus_plugin_rtp_extensions_reset(&rtp.extensions); - janus_core->relay_rtp(session->handle, &rtp); + duktape_janus_core->relay_rtp(session->handle, &rtp); duk_push_int(ctx, 0); return 1; } @@ -1150,7 +1150,7 @@ static duk_ret_t janus_duktape_method_relayrtcp(duk_context *ctx) { janus_mutex_unlock(&duktape_sessions_mutex); /* Send the RTCP packet */ janus_plugin_rtcp rtcp = { .video = is_video, .buffer = (char *)payload, .length = len }; - janus_core->relay_rtcp(session->handle, &rtcp); + duktape_janus_core->relay_rtcp(session->handle, &rtcp); duk_push_int(ctx, 0); return 1; } @@ -1203,7 +1203,7 @@ static duk_ret_t janus_duktape_method_relaytextdata(duk_context *ctx) { .buffer = (char *)payload, .length = len }; - janus_core->relay_data(session->handle, &data); + duktape_janus_core->relay_data(session->handle, &data); janus_refcount_decrease(&session->ref); duk_push_int(ctx, 0); return 1; @@ -1256,7 +1256,7 @@ static duk_ret_t janus_duktape_method_relaybinarydata(duk_context *ctx) { .buffer = (char *)payload, .length = len }; - janus_core->relay_data(session->handle, &data); + duktape_janus_core->relay_data(session->handle, &data); janus_refcount_decrease(&session->ref); duk_push_int(ctx, 0); return 1; @@ -1364,7 +1364,7 @@ static duk_ret_t janus_duktape_method_startrecording(duk_context *ctx) { /* Also send a keyframe request */ session->pli_latest = janus_get_monotonic_time(); JANUS_LOG(LOG_HUGE, "Sending PLI to session %"SCNu32"\n", session->id); - janus_core->send_pli(session->handle); + duktape_janus_core->send_pli(session->handle); } if(drc) { session->drc = drc; @@ -1699,7 +1699,7 @@ int janus_duktape_init(janus_callbacks *callback, const char *config_path) { } /* This is the callback we'll need to invoke to contact the Janus core */ - janus_core = callback; + duktape_janus_core = callback; /* Init the JS script, in case it's needed */ duk_get_global_string(duktape_ctx, "init"); @@ -2445,7 +2445,7 @@ void janus_duktape_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp * gint64 now = janus_get_monotonic_time(); if((now-session->pli_latest) >= ((gint64)session->pli_freq*G_USEC_PER_SEC)) { session->pli_latest = now; - janus_core->send_pli(handle); + duktape_janus_core->send_pli(handle); } } } @@ -2488,7 +2488,7 @@ void janus_duktape_incoming_rtcp(janus_plugin_session *handle, janus_plugin_rtcp uint32_t bitrate = janus_rtcp_get_remb(buf, len); if(bitrate > 0) { /* No limit ~= 10000000 */ - janus_core->send_remb(handle, session->bitrate ? session->bitrate : 10000000); + duktape_janus_core->send_remb(handle, session->bitrate ? session->bitrate : 10000000); } /* If there's an incoming PLI, instead, relay it to the source of the media if any */ if(janus_rtcp_has_pli(buf, len)) { @@ -2497,7 +2497,7 @@ void janus_duktape_incoming_rtcp(janus_plugin_session *handle, janus_plugin_rtcp /* Send a PLI */ session->sender->pli_latest = janus_get_monotonic_time(); JANUS_LOG(LOG_HUGE, "Sending PLI to session %"SCNu32"\n", session->sender->id); - janus_core->send_pli(session->sender->handle); + duktape_janus_core->send_pli(session->sender->handle); janus_mutex_unlock_nodebug(&session->sender->recipients_mutex); } } @@ -2733,7 +2733,7 @@ static void janus_duktape_relay_rtp_packet(gpointer data, gpointer user_data) { if(session->sim_context.need_pli && sender->handle) { /* Send a PLI */ JANUS_LOG(LOG_VERB, "We need a PLI for the simulcast context\n"); - janus_core->send_pli(sender->handle); + duktape_janus_core->send_pli(sender->handle); } /* Do we need to drop this? */ if(!relay) @@ -2787,10 +2787,10 @@ static void janus_duktape_relay_rtp_packet(gpointer data, gpointer user_data) { session->sim_context.changed_substream); } /* Send the packet */ - if(janus_core != NULL) { + if(duktape_janus_core != NULL) { janus_plugin_rtp rtp = { .video = packet->is_video, .buffer = (char *)packet->data, .length = packet->length }; janus_plugin_rtp_extensions_reset(&rtp.extensions); - janus_core->relay_rtp(session->handle, &rtp); + duktape_janus_core->relay_rtp(session->handle, &rtp); } /* Restore the timestamp and sequence number to what the publisher set them to */ packet->data->timestamp = htonl(packet->timestamp); @@ -2803,10 +2803,10 @@ static void janus_duktape_relay_rtp_packet(gpointer data, gpointer user_data) { /* Fix sequence number and timestamp (publisher switching may be involved) */ janus_rtp_header_update(packet->data, &session->rtpctx, packet->is_video, 0); /* Send the packet */ - if(janus_core != NULL) { + if(duktape_janus_core != NULL) { janus_plugin_rtp rtp = { .video = packet->is_video, .buffer = (char *)packet->data, .length = packet->length }; janus_plugin_rtp_extensions_reset(&rtp.extensions); - janus_core->relay_rtp(session->handle, &rtp); + duktape_janus_core->relay_rtp(session->handle, &rtp); } /* Restore the timestamp and sequence number to what the publisher set them to */ packet->data->timestamp = htonl(packet->timestamp); @@ -2827,7 +2827,7 @@ static void janus_duktape_relay_data_packet(gpointer data, gpointer user_data) { !session->accept_data || !g_atomic_int_get(&session->dataready)) { return; } - if(janus_core != NULL) { + if(duktape_janus_core != NULL) { JANUS_LOG(LOG_VERB, "Forwarding %s DataChannel message (%d bytes) to session %"SCNu32"\n", packet->textdata ? "text" : "binary", packet->length, session->id); janus_plugin_data data = { @@ -2837,7 +2837,7 @@ static void janus_duktape_relay_data_packet(gpointer data, gpointer user_data) { .buffer = (char *)packet->data, .length = packet->length }; - janus_core->relay_data(session->handle, &data); + duktape_janus_core->relay_data(session->handle, &data); } return; } diff --git a/plugins/janus_duktape_data.h b/plugins/janus_duktape_data.h index e705df33ba5..384b89ab3e2 100644 --- a/plugins/janus_duktape_data.h +++ b/plugins/janus_duktape_data.h @@ -41,7 +41,7 @@ /* Core pointer and related flags */ extern volatile gint duktape_initialized, duktape_stopping; -extern janus_callbacks *janus_core; +extern janus_callbacks *duktape_janus_core; /* Duktape context: we define context and mutex as extern */ extern duk_context *duktape_ctx; diff --git a/plugins/janus_lua.c b/plugins/janus_lua.c index 452d2716739..0366cb570e6 100644 --- a/plugins/janus_lua.c +++ b/plugins/janus_lua.c @@ -267,7 +267,7 @@ janus_plugin *create(void) { /* Useful stuff */ volatile gint lua_initialized = 0, lua_stopping = 0; -janus_callbacks *janus_core = NULL; +janus_callbacks *lua_janus_core = NULL; /* Lua stuff */ lua_State *lua_state = NULL; @@ -401,7 +401,7 @@ static void *janus_lua_async_event_helper(void *data) { return NULL; if(asev->type == janus_lua_async_event_type_pushevent) { /* Send the event */ - janus_core->push_event(asev->session->handle, &janus_lua_plugin, asev->transaction, asev->event, asev->jsep); + lua_janus_core->push_event(asev->session->handle, &janus_lua_plugin, asev->transaction, asev->event, asev->jsep); } json_decref(asev->event); json_decref(asev->jsep); @@ -571,7 +571,7 @@ static int janus_lua_method_pushevent(lua_State *s) { return 1; } /* No SDP, send the event now */ - int res = janus_core->push_event(session->handle, &janus_lua_plugin, transaction, event, NULL); + int res = lua_janus_core->push_event(session->handle, &janus_lua_plugin, transaction, event, NULL); janus_refcount_decrease(&session->ref); json_decref(event); lua_pushnumber(s, res); @@ -586,7 +586,7 @@ static int janus_lua_method_notifyevent(lua_State *s) { lua_pushnumber(s, -1); return 1; } - if(!janus_core->events_is_enabled()) { + if(!lua_janus_core->events_is_enabled()) { /* Event handlers are disabled in the core, ignoring */ lua_pushnumber(s, 0); return 1; @@ -608,7 +608,7 @@ static int janus_lua_method_notifyevent(lua_State *s) { janus_refcount_increase(&session->ref); janus_mutex_unlock(&lua_sessions_mutex); /* Notify the event */ - janus_core->notify_event(&janus_lua_plugin, session ? session->handle : NULL, event); + lua_janus_core->notify_event(&janus_lua_plugin, session ? session->handle : NULL, event); if(session != NULL) janus_refcount_decrease(&session->ref); lua_pushnumber(s, 0); @@ -624,7 +624,7 @@ static int janus_lua_method_eventsisenabled(lua_State *s) { return 1; } /* Event handlers are disabled in the core, ignoring */ - lua_pushnumber(s, janus_core->events_is_enabled()); + lua_pushnumber(s, lua_janus_core->events_is_enabled()); return 1; } @@ -648,7 +648,7 @@ static int janus_lua_method_closepc(lua_State *s) { janus_refcount_increase(&session->ref); janus_mutex_unlock(&lua_sessions_mutex); /* Close the PeerConnection */ - janus_core->close_pc(session->handle); + lua_janus_core->close_pc(session->handle); lua_pushnumber(s, 0); return 1; } @@ -673,7 +673,7 @@ static int janus_lua_method_endsession(lua_State *s) { janus_refcount_increase(&session->ref); janus_mutex_unlock(&lua_sessions_mutex); /* Close the plugin handle */ - janus_core->end_session(session->handle); + lua_janus_core->end_session(session->handle); lua_pushnumber(s, 0); return 1; } @@ -845,7 +845,7 @@ static int janus_lua_method_setbitrate(lua_State *s) { /* Send a REMB right away too, if the PeerConnection is up */ if(g_atomic_int_get(&session->started)) { /* No limit ~= 10000000 */ - janus_core->send_remb(session->handle, session->bitrate ? session->bitrate : 10000000); + lua_janus_core->send_remb(session->handle, session->bitrate ? session->bitrate : 10000000); } /* Done */ janus_refcount_decrease(&session->ref); @@ -958,7 +958,7 @@ static int janus_lua_method_sendpli(lua_State *s) { /* Send a PLI */ session->pli_latest = janus_get_monotonic_time(); JANUS_LOG(LOG_HUGE, "Sending PLI to session %"SCNu32"\n", session->id); - janus_core->send_pli(session->handle); + lua_janus_core->send_pli(session->handle); /* Done */ janus_refcount_decrease(&session->ref); lua_pushnumber(s, 0); @@ -994,7 +994,7 @@ static int janus_lua_method_relayrtp(lua_State *s) { /* Send the RTP packet */ janus_plugin_rtp rtp = { .video = is_video, .buffer = (char *)payload, .length = len }; janus_plugin_rtp_extensions_reset(&rtp.extensions); - janus_core->relay_rtp(session->handle, &rtp); + lua_janus_core->relay_rtp(session->handle, &rtp); lua_pushnumber(s, 0); return 1; } @@ -1027,7 +1027,7 @@ static int janus_lua_method_relayrtcp(lua_State *s) { janus_mutex_unlock(&lua_sessions_mutex); /* Send the RTCP packet */ janus_plugin_rtcp rtcp = { .video = is_video, .buffer = (char *)payload, .length = len }; - janus_core->relay_rtcp(session->handle, &rtcp); + lua_janus_core->relay_rtcp(session->handle, &rtcp); lua_pushnumber(s, 0); return 1; } @@ -1073,7 +1073,7 @@ static int janus_lua_method_relaytextdata(lua_State *s) { .buffer = (char *)payload, .length = len }; - janus_core->relay_data(session->handle, &data); + lua_janus_core->relay_data(session->handle, &data); janus_refcount_decrease(&session->ref); lua_pushnumber(s, 0); return 1; @@ -1120,7 +1120,7 @@ static int janus_lua_method_relaybinarydata(lua_State *s) { .buffer = (char *)payload, .length = len }; - janus_core->relay_data(session->handle, &data); + lua_janus_core->relay_data(session->handle, &data); janus_refcount_decrease(&session->ref); lua_pushnumber(s, 0); return 1; @@ -1229,7 +1229,7 @@ static int janus_lua_method_startrecording(lua_State *s) { /* Also send a keyframe request */ session->pli_latest = janus_get_monotonic_time(); JANUS_LOG(LOG_HUGE, "Sending PLI to session %"SCNu32"\n", session->id); - janus_core->send_pli(session->handle); + lua_janus_core->send_pli(session->handle); } if(drc) { session->drc = drc; @@ -1521,7 +1521,7 @@ int janus_lua_init(janus_callbacks *callback, const char *config_path) { } /* This is the callback we'll need to invoke to contact the Janus core */ - janus_core = callback; + lua_janus_core = callback; /* Init the Lua script, in case it's needed */ lua_getglobal(lua_state, "init"); @@ -2140,7 +2140,7 @@ void janus_lua_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp *rtp_ if((now-session->pli_latest) >= ((gint64)session->pli_freq*G_USEC_PER_SEC)) { session->pli_latest = now; JANUS_LOG(LOG_HUGE, "Sending PLI to session %"SCNu32"\n", session->id); - janus_core->send_pli(handle); + lua_janus_core->send_pli(handle); } } } @@ -2177,7 +2177,7 @@ void janus_lua_incoming_rtcp(janus_plugin_session *handle, janus_plugin_rtcp *pa guint32 bitrate = janus_rtcp_get_remb(buf, len); if(bitrate > 0) { /* No limit ~= 10000000 */ - janus_core->send_remb(handle, session->bitrate ? session->bitrate : 10000000); + lua_janus_core->send_remb(handle, session->bitrate ? session->bitrate : 10000000); } /* If there's an incoming PLI, instead, relay it to the source of the media if any */ if(janus_rtcp_has_pli(buf, len)) { @@ -2186,7 +2186,7 @@ void janus_lua_incoming_rtcp(janus_plugin_session *handle, janus_plugin_rtcp *pa /* Send a PLI */ session->sender->pli_latest = janus_get_monotonic_time(); JANUS_LOG(LOG_HUGE, "Sending PLI to session %"SCNu32"\n", session->sender->id); - janus_core->send_pli(session->sender->handle); + lua_janus_core->send_pli(session->sender->handle); janus_mutex_unlock_nodebug(&session->sender->recipients_mutex); } } @@ -2398,7 +2398,7 @@ static void janus_lua_relay_rtp_packet(gpointer data, gpointer user_data) { if(session->sim_context.need_pli && sender->handle) { /* Send a PLI */ JANUS_LOG(LOG_VERB, "We need a PLI for the simulcast context\n"); - janus_core->send_pli(sender->handle); + lua_janus_core->send_pli(sender->handle); } /* Do we need to drop this? */ if(!relay) @@ -2440,10 +2440,10 @@ static void janus_lua_relay_rtp_packet(gpointer data, gpointer user_data) { session->sim_context.changed_substream); } /* Send the packet */ - if(janus_core != NULL) { + if(lua_janus_core != NULL) { janus_plugin_rtp rtp = { .video = packet->is_video, .buffer = (char *)packet->data, .length = packet->length }; janus_plugin_rtp_extensions_reset(&rtp.extensions); - janus_core->relay_rtp(session->handle, &rtp); + lua_janus_core->relay_rtp(session->handle, &rtp); } /* Restore the timestamp and sequence number to what the publisher set them to */ packet->data->timestamp = htonl(packet->timestamp); @@ -2456,10 +2456,10 @@ static void janus_lua_relay_rtp_packet(gpointer data, gpointer user_data) { /* Fix sequence number and timestamp (publisher switching may be involved) */ janus_rtp_header_update(packet->data, &session->rtpctx, packet->is_video, 0); /* Send the packet */ - if(janus_core != NULL) { + if(lua_janus_core != NULL) { janus_plugin_rtp rtp = { .video = packet->is_video, .buffer = (char *)packet->data, .length = packet->length }; janus_plugin_rtp_extensions_reset(&rtp.extensions); - janus_core->relay_rtp(session->handle, &rtp); + lua_janus_core->relay_rtp(session->handle, &rtp); } /* Restore the timestamp and sequence number to what the publisher set them to */ packet->data->timestamp = htonl(packet->timestamp); @@ -2480,7 +2480,7 @@ static void janus_lua_relay_data_packet(gpointer data, gpointer user_data) { !session->accept_data || !g_atomic_int_get(&session->dataready)) { return; } - if(janus_core != NULL) { + if(lua_janus_core != NULL) { JANUS_LOG(LOG_VERB, "Forwarding %s DataChannel message (%d bytes) to session %"SCNu32"\n", packet->textdata ? "text" : "binary", packet->length, session->id); janus_plugin_data data = { @@ -2490,7 +2490,7 @@ static void janus_lua_relay_data_packet(gpointer data, gpointer user_data) { .buffer = (char *)packet->data, .length = packet->length }; - janus_core->relay_data(session->handle, &data); + lua_janus_core->relay_data(session->handle, &data); } return; } diff --git a/plugins/janus_lua_data.h b/plugins/janus_lua_data.h index 2b499545464..38cb60a51f9 100644 --- a/plugins/janus_lua_data.h +++ b/plugins/janus_lua_data.h @@ -41,7 +41,7 @@ /* Core pointer and related flags */ extern volatile gint lua_initialized, lua_stopping; -extern janus_callbacks *janus_core; +extern janus_callbacks *lua_janus_core; /* Lua state: we define state and mutex as extern */ extern lua_State *lua_state; From 0ba74fb4104beb65747a681302082897a9314186 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 8 Feb 2021 11:53:42 +0100 Subject: [PATCH 07/63] Fixed broken AV1 post-processing --- postprocessing/pp-av1.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/postprocessing/pp-av1.c b/postprocessing/pp-av1.c index c824ccba047..4b7493eb5bc 100644 --- a/postprocessing/pp-av1.c +++ b/postprocessing/pp-av1.c @@ -96,12 +96,13 @@ int janus_pp_av1_create(char *destination, char *metadata, gboolean faststart) { #ifdef USE_CODECPAR #if LIBAVCODEC_VER_AT_LEAST(57, 25) AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AV1); -#endif +#else if(!codec) { /* Error opening video codec */ JANUS_LOG(LOG_ERR, "Encoder not available\n"); return -1; } +#endif fctx->video_codec = codec; fctx->oformat->video_codec = codec->id; vStream = avformat_new_stream(fctx, codec); @@ -249,8 +250,8 @@ static void janus_pp_av1_parse_sh(char *buffer, uint16_t *width, uint16_t *heigh if(value) initial_display_delay = TRUE; /* Skip operating_points_cnt_minus_1 (5 bits) */ - value = janus_pp_av1_getbits(base, 5, &offset)+1; - for(i=0; i Date: Mon, 8 Feb 2021 15:17:56 +0100 Subject: [PATCH 08/63] Initialize VideoRoom participant recording state when room recording is active (fixes #2550) --- plugins/janus_videoroom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index 6a0976458fb..7174dd004e9 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -7521,6 +7521,7 @@ static void *janus_videoroom_handler(void *data) { /* Is this room recorded, or are we recording this publisher already? */ janus_mutex_lock(&participant->rec_mutex); if(videoroom->record || participant->recording_active) { + participant->recording_active = TRUE; janus_videoroom_recorder_create(participant, participant->audio, participant->video, participant->data); } janus_mutex_unlock(&participant->rec_mutex); From b81dd6d1ed11363f78265f727b8892c99e765e84 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 8 Feb 2021 16:26:19 +0100 Subject: [PATCH 09/63] Allow forcing audio/video codec for VideoRoom publishers via query string --- html/videoroomtest.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/html/videoroomtest.js b/html/videoroomtest.js index c8a533c5cfb..b73bd8cc57c 100644 --- a/html/videoroomtest.js +++ b/html/videoroomtest.js @@ -66,6 +66,8 @@ var bitrateTimer = []; var doSimulcast = (getQueryStringValue("simulcast") === "yes" || getQueryStringValue("simulcast") === "true"); var doSimulcast2 = (getQueryStringValue("simulcast2") === "yes" || getQueryStringValue("simulcast2") === "true"); +var acodec = (getQueryStringValue("acodec") !== "" ? getQueryStringValue("acodec") : null); +var vcodec = (getQueryStringValue("vcodec") !== "" ? getQueryStringValue("vcodec") : null); var subscriber_mode = (getQueryStringValue("subscriber-mode") === "yes" || getQueryStringValue("subscriber-mode") === "true"); $(document).ready(function() { @@ -426,7 +428,12 @@ function publishOwnFeed(useAudio) { // a codec will only work if: (1) the codec is actually in the SDP (and // so the browser supports it), and (2) the codec is in the list of // allowed codecs in a room. With respect to the point (2) above, - // refer to the text in janus.plugin.videoroom.jcfg for more details + // refer to the text in janus.plugin.videoroom.jcfg for more details. + // We allow people to specify a codec via query string, for demo purposes + if(acodec) + publish["audiocodec"] = acodec; + if(vcodec) + publish["videocodec"] = vcodec; sfutest.send({ message: publish, jsep: jsep }); }, error: function(error) { From 41399db99f0ac6eac5c19dff9080b9336ae60169 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 8 Feb 2021 16:27:14 +0100 Subject: [PATCH 10/63] Allow up to 5 (rather than 3) audio/video codecs in the same VideoRoom --- plugins/janus_videoroom.c | 84 +++++++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 20 deletions(-) diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index 7174dd004e9..e985ca27dcf 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -1467,8 +1467,8 @@ typedef struct janus_videoroom { uint32_t bitrate; /* Global bitrate limit */ gboolean bitrate_cap; /* Whether the above limit is insormountable */ uint16_t fir_freq; /* Regular FIR frequency (0=disabled) */ - janus_audiocodec acodec[3]; /* Audio codec(s) to force on publishers */ - janus_videocodec vcodec[3]; /* Video codec(s) to force on publishers */ + janus_audiocodec acodec[5]; /* Audio codec(s) to force on publishers */ + janus_videocodec vcodec[5]; /* Video codec(s) to force on publishers */ char *vp9_profile; /* VP9 codec profile to prefer, if more are negotiated */ char *h264_profile; /* H.264 codec profile to prefer, if more are negotiated */ gboolean do_opusfec; /* Whether inband FEC must be negotiated (note: only available for Opus) */ @@ -1836,6 +1836,14 @@ static void janus_videoroom_codecstr(janus_videoroom *videoroom, char *audio_cod g_strlcat(audio_codecs, split, str_len); g_strlcat(audio_codecs, janus_audiocodec_name(videoroom->acodec[2]), str_len); } + if (videoroom->acodec[3] != JANUS_AUDIOCODEC_NONE) { + g_strlcat(audio_codecs, split, str_len); + g_strlcat(audio_codecs, janus_audiocodec_name(videoroom->acodec[3]), str_len); + } + if (videoroom->acodec[4] != JANUS_AUDIOCODEC_NONE) { + g_strlcat(audio_codecs, split, str_len); + g_strlcat(audio_codecs, janus_audiocodec_name(videoroom->acodec[4]), str_len); + } } if (video_codecs) { video_codecs[0] = 0; @@ -1848,6 +1856,14 @@ static void janus_videoroom_codecstr(janus_videoroom *videoroom, char *audio_cod g_strlcat(video_codecs, split, str_len); g_strlcat(video_codecs, janus_videocodec_name(videoroom->vcodec[2]), str_len); } + if (videoroom->vcodec[3] != JANUS_VIDEOCODEC_NONE) { + g_strlcat(video_codecs, split, str_len); + g_strlcat(video_codecs, janus_videocodec_name(videoroom->vcodec[3]), str_len); + } + if (videoroom->vcodec[4] != JANUS_VIDEOCODEC_NONE) { + g_strlcat(video_codecs, split, str_len); + g_strlcat(video_codecs, janus_videocodec_name(videoroom->vcodec[4]), str_len); + } } } @@ -2266,6 +2282,8 @@ int janus_videoroom_init(janus_callbacks *callback, const char *config_path) { videoroom->acodec[0] = JANUS_AUDIOCODEC_OPUS; videoroom->acodec[1] = JANUS_AUDIOCODEC_NONE; videoroom->acodec[2] = JANUS_AUDIOCODEC_NONE; + videoroom->acodec[3] = JANUS_AUDIOCODEC_NONE; + videoroom->acodec[4] = JANUS_AUDIOCODEC_NONE; /* Check if we're forcing a different single codec, or allowing more than one */ if(audiocodec && audiocodec->value) { gchar **list = g_strsplit(audiocodec->value, ",", 4); @@ -2273,7 +2291,7 @@ int janus_videoroom_init(janus_callbacks *callback, const char *config_path) { if(codec != NULL) { int i=0; while(codec != NULL) { - if(i == 3) { + if(i == 5) { JANUS_LOG(LOG_WARN, "Ignoring extra audio codecs: %s\n", codec); break; } @@ -2289,6 +2307,8 @@ int janus_videoroom_init(janus_callbacks *callback, const char *config_path) { videoroom->vcodec[0] = JANUS_VIDEOCODEC_VP8; videoroom->vcodec[1] = JANUS_VIDEOCODEC_NONE; videoroom->vcodec[2] = JANUS_VIDEOCODEC_NONE; + videoroom->vcodec[3] = JANUS_VIDEOCODEC_NONE; + videoroom->vcodec[4] = JANUS_VIDEOCODEC_NONE; /* Check if we're forcing a different single codec, or allowing more than one */ if(videocodec && videocodec->value) { gchar **list = g_strsplit(videocodec->value, ",", 4); @@ -2296,7 +2316,7 @@ int janus_videoroom_init(janus_callbacks *callback, const char *config_path) { if(codec != NULL) { int i=0; while(codec != NULL) { - if(i == 3) { + if(i == 5) { JANUS_LOG(LOG_WARN, "Ignoring extra video codecs: %s\n", codec); break; } @@ -2310,19 +2330,25 @@ int janus_videoroom_init(janus_callbacks *callback, const char *config_path) { } if(vp9profile && vp9profile->value && (videoroom->vcodec[0] == JANUS_VIDEOCODEC_VP9 || videoroom->vcodec[1] == JANUS_VIDEOCODEC_VP9 || - videoroom->vcodec[2] == JANUS_VIDEOCODEC_VP9)) { + videoroom->vcodec[2] == JANUS_VIDEOCODEC_VP9 || + videoroom->vcodec[3] == JANUS_VIDEOCODEC_VP9 || + videoroom->vcodec[4] == JANUS_VIDEOCODEC_VP9)) { videoroom->vp9_profile = g_strdup(vp9profile->value); } if(h264profile && h264profile->value && (videoroom->vcodec[0] == JANUS_VIDEOCODEC_H264 || videoroom->vcodec[1] == JANUS_VIDEOCODEC_H264 || - videoroom->vcodec[2] == JANUS_VIDEOCODEC_H264)) { + videoroom->vcodec[2] == JANUS_VIDEOCODEC_H264 || + videoroom->vcodec[3] == JANUS_VIDEOCODEC_H264 || + videoroom->vcodec[4] == JANUS_VIDEOCODEC_H264)) { videoroom->h264_profile = g_strdup(h264profile->value); } if(fec && fec->value) { videoroom->do_opusfec = janus_is_true(fec->value); if(videoroom->acodec[0] != JANUS_AUDIOCODEC_OPUS && videoroom->acodec[1] != JANUS_AUDIOCODEC_OPUS && - videoroom->acodec[2] != JANUS_AUDIOCODEC_OPUS) { + videoroom->acodec[2] != JANUS_AUDIOCODEC_OPUS && + videoroom->acodec[3] != JANUS_AUDIOCODEC_OPUS && + videoroom->acodec[4] != JANUS_AUDIOCODEC_OPUS) { videoroom->do_opusfec = FALSE; JANUS_LOG(LOG_WARN, "Inband FEC is only supported for rooms that allow Opus: disabling it...\n"); } @@ -2330,7 +2356,9 @@ int janus_videoroom_init(janus_callbacks *callback, const char *config_path) { if(svc && svc->value && janus_is_true(svc->value)) { if(videoroom->vcodec[0] == JANUS_VIDEOCODEC_VP9 && videoroom->vcodec[1] == JANUS_VIDEOCODEC_NONE && - videoroom->vcodec[2] == JANUS_VIDEOCODEC_NONE) { + videoroom->vcodec[2] == JANUS_VIDEOCODEC_NONE && + videoroom->vcodec[3] == JANUS_VIDEOCODEC_NONE && + videoroom->vcodec[4] == JANUS_VIDEOCODEC_NONE) { videoroom->do_svc = TRUE; } else { JANUS_LOG(LOG_WARN, "SVC is only supported, in an experimental way, for VP9 only rooms: disabling it...\n"); @@ -2945,7 +2973,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi if(codec != NULL) { int i=0; while(codec != NULL) { - if(i == 3) { + if(i == 5) { break; } if(strlen(codec) == 0 || JANUS_AUDIOCODEC_NONE == janus_audiocodec_from_name(codec)) { @@ -2968,7 +2996,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi if(codec != NULL) { int i=0; while(codec != NULL) { - if(i == 3) { + if(i == 5) { break; } if(strlen(codec) == 0 || JANUS_VIDEOCODEC_NONE == janus_videocodec_from_name(codec)) { @@ -3113,6 +3141,8 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi videoroom->acodec[0] = JANUS_AUDIOCODEC_OPUS; videoroom->acodec[1] = JANUS_AUDIOCODEC_NONE; videoroom->acodec[2] = JANUS_AUDIOCODEC_NONE; + videoroom->acodec[3] = JANUS_AUDIOCODEC_NONE; + videoroom->acodec[4] = JANUS_AUDIOCODEC_NONE; /* Check if we're forcing a different single codec, or allowing more than one */ if(audiocodec) { const char *audiocodec_value = json_string_value(audiocodec); @@ -3121,7 +3151,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi if(codec != NULL) { int i=0; while(codec != NULL) { - if(i == 3) { + if(i == 5) { JANUS_LOG(LOG_WARN, "Ignoring extra audio codecs: %s\n", codec); break; } @@ -3137,6 +3167,8 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi videoroom->vcodec[0] = JANUS_VIDEOCODEC_VP8; videoroom->vcodec[1] = JANUS_VIDEOCODEC_NONE; videoroom->vcodec[2] = JANUS_VIDEOCODEC_NONE; + videoroom->vcodec[3] = JANUS_VIDEOCODEC_NONE; + videoroom->vcodec[4] = JANUS_VIDEOCODEC_NONE; /* Check if we're forcing a different single codec, or allowing more than one */ if(videocodec) { const char *videocodec_value = json_string_value(videocodec); @@ -3145,7 +3177,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi if(codec != NULL) { int i=0; while(codec != NULL) { - if(i == 3) { + if(i == 5) { JANUS_LOG(LOG_WARN, "Ignoring extra video codecs: %s\n", codec); break; } @@ -3160,20 +3192,26 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi const char *vp9_profile = json_string_value(vp9profile); if(vp9_profile && (videoroom->vcodec[0] == JANUS_VIDEOCODEC_VP9 || videoroom->vcodec[1] == JANUS_VIDEOCODEC_VP9 || - videoroom->vcodec[2] == JANUS_VIDEOCODEC_VP9)) { + videoroom->vcodec[2] == JANUS_VIDEOCODEC_VP9 || + videoroom->vcodec[3] == JANUS_VIDEOCODEC_VP9 || + videoroom->vcodec[4] == JANUS_VIDEOCODEC_VP9)) { videoroom->vp9_profile = g_strdup(vp9_profile); } const char *h264_profile = json_string_value(h264profile); if(h264_profile && (videoroom->vcodec[0] == JANUS_VIDEOCODEC_H264 || videoroom->vcodec[1] == JANUS_VIDEOCODEC_H264 || - videoroom->vcodec[2] == JANUS_VIDEOCODEC_H264)) { + videoroom->vcodec[2] == JANUS_VIDEOCODEC_H264 || + videoroom->vcodec[3] == JANUS_VIDEOCODEC_H264 || + videoroom->vcodec[4] == JANUS_VIDEOCODEC_H264)) { videoroom->h264_profile = g_strdup(h264_profile); } if(fec) { videoroom->do_opusfec = json_is_true(fec); if(videoroom->acodec[0] != JANUS_AUDIOCODEC_OPUS && videoroom->acodec[1] != JANUS_AUDIOCODEC_OPUS && - videoroom->acodec[2] != JANUS_AUDIOCODEC_OPUS) { + videoroom->acodec[2] != JANUS_AUDIOCODEC_OPUS && + videoroom->acodec[3] != JANUS_AUDIOCODEC_OPUS && + videoroom->acodec[4] != JANUS_AUDIOCODEC_OPUS) { videoroom->do_opusfec = FALSE; JANUS_LOG(LOG_WARN, "Inband FEC is only supported for rooms that allow Opus: disabling it...\n"); } @@ -3181,7 +3219,9 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi if(svc && json_is_true(svc)) { if(videoroom->vcodec[0] == JANUS_VIDEOCODEC_VP9 && videoroom->vcodec[1] == JANUS_VIDEOCODEC_NONE && - videoroom->vcodec[2] == JANUS_VIDEOCODEC_NONE) { + videoroom->vcodec[2] == JANUS_VIDEOCODEC_NONE && + videoroom->vcodec[3] == JANUS_VIDEOCODEC_NONE && + videoroom->vcodec[4] == JANUS_VIDEOCODEC_NONE) { videoroom->do_svc = TRUE; } else { JANUS_LOG(LOG_WARN, "SVC is only supported, in an experimental way, for VP9 only rooms: disabling it...\n"); @@ -6523,7 +6563,9 @@ static void *janus_videoroom_handler(void *data) { if(acodec == JANUS_AUDIOCODEC_NONE || (acodec != participant->room->acodec[0] && acodec != participant->room->acodec[1] && - acodec != participant->room->acodec[2])) { + acodec != participant->room->acodec[2] && + acodec != participant->room->acodec[3] && + acodec != participant->room->acodec[4])) { JANUS_LOG(LOG_ERR, "Participant asked for audio codec '%s', but it's not allowed (room %s, user %s)\n", json_string_value(audiocodec), participant->room_id_str, participant->user_id_str); janus_refcount_decrease(&participant->ref); @@ -6559,7 +6601,9 @@ static void *janus_videoroom_handler(void *data) { if(vcodec == JANUS_VIDEOCODEC_NONE || (vcodec != participant->room->vcodec[0] && vcodec != participant->room->vcodec[1] && - vcodec != participant->room->vcodec[2])) { + vcodec != participant->room->vcodec[2] && + vcodec != participant->room->vcodec[3] && + vcodec != participant->room->vcodec[4])) { JANUS_LOG(LOG_ERR, "Participant asked for video codec '%s', but it's not allowed (room %s, user %s)\n", json_string_value(videocodec), participant->room_id_str, participant->user_id_str); janus_refcount_decrease(&participant->ref); @@ -7346,7 +7390,7 @@ static void *janus_videoroom_handler(void *data) { /* Check the codecs we can use, or the ones we should */ if(participant->acodec == JANUS_AUDIOCODEC_NONE) { int i=0; - for(i=0; i<3; i++) { + for(i=0; i<5; i++) { if(videoroom->acodec[i] == JANUS_AUDIOCODEC_NONE) continue; if(janus_sdp_get_codec_pt(offer, janus_audiocodec_name(videoroom->acodec[i])) != -1) { @@ -7365,7 +7409,7 @@ static void *janus_videoroom_handler(void *data) { char *h264_profile = videoroom->h264_profile; if(participant->vcodec == JANUS_VIDEOCODEC_NONE) { int i=0; - for(i=0; i<3; i++) { + for(i=0; i<5; i++) { if(videoroom->vcodec[i] == JANUS_VIDEOCODEC_NONE) continue; if(videoroom->vcodec[i] == JANUS_VIDEOCODEC_VP9 && vp9_profile) { From 119d220c2e6324dd2233d8f93868fcaa1ae229fd Mon Sep 17 00:00:00 2001 From: Aleksander Guryanov Date: Tue, 9 Feb 2021 20:33:23 +0700 Subject: [PATCH 11/63] Update janus.d.ts (#2553) Function getBitrate() actually returns a string --- npm/janus.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/janus.d.ts b/npm/janus.d.ts index f81736e4ee6..bbd6cf017de 100644 --- a/npm/janus.d.ts +++ b/npm/janus.d.ts @@ -156,7 +156,7 @@ declare namespace JanusJS { isVideoMuted(): boolean; muteVideo(): void; unmuteVideo(): void; - getBitrate(): number; + getBitrate(): string; hangup(sendRequest?: boolean): void; detach(params: any): void; } From 66cf343cefbc4954f330ef4a251330ffd233bae6 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 9 Feb 2021 16:05:37 +0100 Subject: [PATCH 12/63] Add resolution and bitrate to Record&Play playback --- html/recordplaytest.js | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/html/recordplaytest.js b/html/recordplaytest.js index 37b1ba826a8..9000740458f 100644 --- a/html/recordplaytest.js +++ b/html/recordplaytest.js @@ -171,19 +171,6 @@ $(document).ready(function() { Janus.log("The ID of the current recording is " + id); recordingId = id; } - } else if(event === 'slow_link') { - var uplink = result["uplink"]; - if(uplink !== 0) { - // Janus detected issues when receiving our media, let's slow down - bandwidth = parseInt(bandwidth / 1.5); - recordplay.send({ - message: { - request: 'configure', - 'video-bitrate-max': bandwidth, // Reduce the bitrate - 'video-keyframe-interval': 15000 // Keep the 15 seconds key frame interval - } - }); - } } else if(event === 'playing') { Janus.log("Playout has started!"); } else if(event === 'stopped') { @@ -290,6 +277,26 @@ $(document).ready(function() { } else { spinner.spin(); } + if($('#curres').length === 0) { + $('#videobox').append( + '' + + ''); + $("#video").bind("playing", function () { + var width = this.videoWidth; + var height = this.videoHeight; + $('#curres').text(width + 'x' + height); + }); + recordplay.bitrateTimer = setInterval(function() { + // Display updated bitrate, if supported + var bitrate = recordplay.getBitrate(); + $('#curbw').text(bitrate); + var video = $('#thevideo').get(0); + var width = video.videoWidth; + var height = video.videoHeight; + if(width > 0 && height > 0) + $('#curres').text(width + 'x' + height); + }, 1000); + } // Show the video, hide the spinner and show the resolution when we get a playing event $("#thevideo").bind("playing", function () { $('#waitingvideo').remove(); @@ -337,6 +344,9 @@ $(document).ready(function() { if(spinner) spinner.stop(); spinner = null; + if(recordplay.bitrateTimer) + clearInterval(recordplay.bitrateTimer); + delete recordplay.bitrateTimer; $('#videobox').empty(); $("#videobox").parent().unblock(); $('#video').hide(); From 8ab7a004009831fc4d0e8b2ef84155030bdfbb2e Mon Sep 17 00:00:00 2001 From: Alessandro Toppi Date: Tue, 9 Feb 2021 16:51:37 +0100 Subject: [PATCH 13/63] Initialize packet.is_rtp to false. --- plugins/janus_streaming.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/janus_streaming.c b/plugins/janus_streaming.c index dcc85a5aa1e..2f09777bc3a 100644 --- a/plugins/janus_streaming.c +++ b/plugins/janus_streaming.c @@ -8106,6 +8106,7 @@ static void *janus_streaming_relay_thread(void *data) { JANUS_LOG(LOG_HUGE, "[%s] Got audio RTCP feedback: SSRC %"SCNu32"\n", name, janus_rtcp_get_sender_ssrc(buffer, bytes)); /* Relay on all sessions */ + packet.is_rtp = FALSE; packet.is_video = FALSE; packet.data = (janus_rtp_header *)buffer; packet.length = bytes; @@ -8132,6 +8133,7 @@ static void *janus_streaming_relay_thread(void *data) { JANUS_LOG(LOG_HUGE, "[%s] Got video RTCP feedback: SSRC %"SCNu32"\n", name, janus_rtcp_get_sender_ssrc(buffer, bytes)); /* Relay on all sessions */ + packet.is_rtp = FALSE; packet.is_video = TRUE; packet.data = (janus_rtp_header *)buffer; packet.length = bytes; From 26f59581c22d651eb8aa7e51215c64a3f897e04a Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Wed, 10 Feb 2021 16:51:19 +0100 Subject: [PATCH 14/63] Fixed small leak in VideoRoom --- plugins/janus_videoroom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index e985ca27dcf..a144e043716 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -7640,10 +7640,10 @@ static void *janus_videoroom_handler(void *data) { } s = s->next; } - janus_refcount_decrease(&videoroom->ref); janus_mutex_unlock(&participant->subscribers_mutex); json_decref(update); } + janus_refcount_decrease(&videoroom->ref); json_decref(event); json_decref(jsep); } From ad8bf7925c8efe02635087296c2b841a8942889c Mon Sep 17 00:00:00 2001 From: Alessandro Amirante Date: Thu, 11 Feb 2021 17:49:25 +0100 Subject: [PATCH 15/63] Fix typo in videoroom docs. --- plugins/janus_videoroom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index a144e043716..9d0ad5443fc 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -104,7 +104,7 @@ room-: { * synchronous error response even for asynchronous requests. * * \c create , \c destroy , \c edit , \c exists, \c list, \c allowed, - * \c kick , \c moderate , \c enable_recording , \listparticipants + * \c kick , \c moderate , \c enable_recording , \c listparticipants * and \c listforwarders are synchronous requests, which means you'll * get a response directly within the context of the transaction. * \c create allows you to create a new video room dynamically, as an From af8cc6e9f8b94b19d161f35edf339a67c107249f Mon Sep 17 00:00:00 2001 From: Nadin Zajimovic Date: Fri, 12 Feb 2021 09:40:36 +0100 Subject: [PATCH 16/63] if inviting on destroy, send BYE instead of 480 response (#2554) --- plugins/janus_sip.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/janus_sip.c b/plugins/janus_sip.c index 25fd593fd21..492410ac3f3 100644 --- a/plugins/janus_sip.c +++ b/plugins/janus_sip.c @@ -2558,13 +2558,15 @@ static void janus_sip_hangup_media_internal(janus_plugin_session *handle) { session->media.autoaccept_reinvites = TRUE; session->media.ready = FALSE; session->media.on_hold = FALSE; - janus_sip_call_update_status(session, janus_sip_call_status_closing); - if(g_atomic_int_get(&session->established)) + /* Send a BYE or respond with 480 */ + if(g_atomic_int_get(&session->established) || session->status == janus_sip_call_status_inviting) nua_bye(session->stack->s_nh_i, TAG_END()); else nua_respond(session->stack->s_nh_i, 480, sip_status_phrase(480), TAG_END()); + janus_sip_call_update_status(session, janus_sip_call_status_closing); + /* Notify the operation */ json_t *event = json_object(); json_object_set_new(event, "sip", json_string("event")); From ad54495df09e8b96386df40b96b4212fe36a92b7 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Fri, 12 Feb 2021 15:28:21 +0100 Subject: [PATCH 17/63] Add new option to configure ICE nomination mode, if libnice is recent enough (#2541) * Add new option to configure ICE nomination mode, if libnice is recent enough * Added support for libnice keepalive-conncheck property --- conf/janus.jcfg.sample.in | 12 +++++++++++- configure.ac | 6 ++++++ ice.c | 39 +++++++++++++++++++++++++++++++++++++++ ice.h | 18 +++++++++++++++++- janus.c | 15 +++++++++++++++ 5 files changed, 88 insertions(+), 2 deletions(-) diff --git a/conf/janus.jcfg.sample.in b/conf/janus.jcfg.sample.in index 7b9c3840623..d1a4a0b5188 100644 --- a/conf/janus.jcfg.sample.in +++ b/conf/janus.jcfg.sample.in @@ -239,7 +239,15 @@ media: { # configured to do full-trickle (Janus also trickles its candidates to # users) rather than the default half-trickle (Janus supports trickle # candidates from users, but sends its own within the SDP), and whether -# it should work in ICE-Lite mode (by default it doesn't). Finally, +# it should work in ICE-Lite mode (by default it doesn't). If libnice is +# at least 0.1.15, you can choose which ICE nomination mode to use: valid +# values are "regular" and "aggressive" (the default depends on the libnice +# version itself; if we can set it, we set regular nomination). You can +# also configure whether to use connectivity checks as keep-alives, which +# might help detecting when a peer is no longer available (notice that +# current libnice master is breaking connections after 50 seconds when +# keepalive-conncheck is being used, so if you want to use it, better +# sticking to 0.1.18 until the issue is addressed upstream). Finally, # you can also enable ICE-TCP support (beware that this may lead to problems # if you do not enable ICE Lite as well), choose which interfaces should # be used for gathering candidates, and enable or disable the @@ -249,6 +257,8 @@ nat: { #stun_port = 3478 nice_debug = false #full_trickle = true + #ice_nomination = "regular" + #ice_keepalive_conncheck = true #ice_lite = true #ice_tcp = true diff --git a/configure.ac b/configure.ac index 6e5cf542baa..f305d527598 100644 --- a/configure.ac +++ b/configure.ac @@ -402,6 +402,12 @@ AC_CHECK_LIB([nice], [AC_MSG_NOTICE([libnice version does not have nice_agent_close_async])] ) +AC_CHECK_LIB([nice], + [nice_agent_new_full], + [AC_DEFINE(HAVE_ICE_NOMINATION)], + [AC_MSG_NOTICE([libnice version does not have nice_agent_new_full])] + ) + AC_CHECK_LIB([dl], [dlopen], [JANUS_MANUAL_LIBS="${JANUS_MANUAL_LIBS} -ldl"], diff --git a/ice.c b/ice.c index 8ebaaeefe50..fb1eb38a338 100644 --- a/ice.c +++ b/ice.c @@ -101,6 +101,41 @@ gboolean janus_ice_is_ipv6_enabled(void) { return janus_ipv6_enabled; } +#ifdef HAVE_ICE_NOMINATION +/* Since libnice 0.1.15, we can configure the ICE nomination mode: it was + * always "aggressive" before, we set it to "regular" by default if we can */ +static NiceNominationMode janus_ice_nomination = NICE_NOMINATION_MODE_REGULAR; +void janus_ice_set_nomination_mode(const char *nomination) { + if(nomination == NULL) { + JANUS_LOG(LOG_WARN, "Invalid ICE nomination mode, falling back to 'regular'\n"); + } else if(!strcasecmp(nomination, "regular")) { + JANUS_LOG(LOG_INFO, "Configuring Janus to use ICE regular nomination\n"); + janus_ice_nomination = NICE_NOMINATION_MODE_REGULAR; + } else if(!strcasecmp(nomination, "aggressive")) { + JANUS_LOG(LOG_INFO, "Configuring Janus to use ICE aggressive nomination\n"); + janus_ice_nomination = NICE_NOMINATION_MODE_AGGRESSIVE; + } else { + JANUS_LOG(LOG_WARN, "Unsupported ICE nomination mode '%s', falling back to 'regular'\n", nomination); + } +} +const char *janus_ice_get_nomination_mode(void) { + return (janus_ice_nomination == NICE_NOMINATION_MODE_REGULAR ? "regular" : "aggressive"); +} +#endif + +/* Keepalive via connectivity checks */ +static gboolean janus_ice_keepalive_connckecks = FALSE; +void janus_ice_set_keepalive_conncheck_enabled(gboolean enabled) { + janus_ice_keepalive_connckecks = enabled; + if(janus_ice_keepalive_connckecks) { + JANUS_LOG(LOG_INFO, "Using connectivity checks as PeerConnection keep-alives\n"); + JANUS_LOG(LOG_WARN, "Notice that the current libnice master is breaking connections after 50s when keepalive-conncheck enabled. As such, better to stick to 0.1.18 until the issue is addressed upstream\n"); + } +} +gboolean janus_ice_is_keepalive_conncheck_enabled(void) { + return janus_ice_keepalive_connckecks; +} + /* Opaque IDs set by applications are by default only passed to event handlers * for correlation purposes, but not sent back to the user or application in * the related Janus API responses or events, unless configured otherwise */ @@ -3461,6 +3496,10 @@ int janus_ice_setup_local(janus_ice_handle *handle, int offer, int audio, int vi "main-context", handle->mainctx, "reliable", FALSE, "full-mode", janus_ice_lite_enabled ? FALSE : TRUE, +#ifdef HAVE_ICE_NOMINATION + "nomination-mode", janus_ice_nomination, +#endif + "keepalive-conncheck", janus_ice_keepalive_connckecks ? FALSE : TRUE, #ifdef HAVE_LIBNICE_TCP "ice-udp", TRUE, "ice-tcp", janus_ice_tcp_enabled ? TRUE : FALSE, diff --git a/ice.h b/ice.h index 8fe22c5c330..015e940306f 100644 --- a/ice.h +++ b/ice.h @@ -129,6 +129,22 @@ gboolean janus_ice_is_mdns_enabled(void); /*! \brief Method to check whether IPv6 candidates are enabled/supported or not * @returns true if IPv6 candidates are enabled/supported, false otherwise */ gboolean janus_ice_is_ipv6_enabled(void); +#ifdef HAVE_ICE_NOMINATION +/*! \brief Method to configure the ICE nomination mode (regular or aggressive) + * @param[in] nomination The ICE nomination mode (regular or aggressive) */ +void janus_ice_set_nomination_mode(const char *nomination); +/*! \brief Method to return a string description of the configured ICE nomination mode + * @returns "regular" or "aggressive" */ +const char *janus_ice_get_nomination_mode(void); +#endif +/*! \brief Method to enable/disable connectivity checks as keepalives for PeerConnections. + * \note The main rationale behind this setting is provided in the libnice documentation: + * https://libnice.freedesktop.org/libnice/NiceAgent.html#NiceAgent--keepalive-conncheck + * @param[in] enabled Whether the functionality should be enabled or disabled */ +void janus_ice_set_keepalive_conncheck_enabled(gboolean enabled); +/*! \brief Method to check whether connectivity checks will be used as keepalives + * @returns true if enabled, false (default) otherwise */ +gboolean janus_ice_is_keepalive_conncheck_enabled(void); /*! \brief Method to modify the min NACK value (i.e., the minimum time window of packets per handle to store for retransmissions) * @param[in] mnq The new min NACK value */ void janus_set_min_nack_queue(uint16_t mnq); @@ -140,7 +156,7 @@ uint16_t janus_get_min_nack_queue(void); * keyframe, as any missing packet won't be needed since the keyframe will allow the * media recipient to still restore a complete image anyway. Since this optimization * seems to cause some issues in some edge cases, it's disabled by default. - * @param[in] optimize Whether the opzimization should be enabled or disabled */ + * @param[in] optimize Whether the optimization should be enabled or disabled */ void janus_set_nack_optimizations_enabled(gboolean optimize); /*! \brief Method to check whether NACK optimizations on outgoing keyframes are enabled or not * @returns optimize if optimizations are enabled, false otherwise */ diff --git a/janus.c b/janus.c index 7e103a15f36..db1ca896893 100644 --- a/janus.c +++ b/janus.c @@ -346,6 +346,10 @@ static json_t *janus_info(const char *transaction) { json_object_set_new(info, "ipv6", janus_ice_is_ipv6_enabled() ? json_true() : json_false()); json_object_set_new(info, "ice-lite", janus_ice_is_ice_lite_enabled() ? json_true() : json_false()); json_object_set_new(info, "ice-tcp", janus_ice_is_ice_tcp_enabled() ? json_true() : json_false()); +#ifdef HAVE_ICE_NOMINATION + json_object_set_new(info, "ice-nomination", json_string(janus_ice_get_nomination_mode())); +#endif + json_object_set_new(info, "ice-keepalive-conncheck", janus_ice_is_keepalive_conncheck_enabled() ? json_true() : json_false()); json_object_set_new(info, "full-trickle", janus_ice_is_full_trickle_enabled() ? json_true() : json_false()); json_object_set_new(info, "mdns-enabled", janus_ice_is_mdns_enabled() ? json_true() : json_false()); json_object_set_new(info, "min-nack-queue", json_integer(janus_get_min_nack_queue())); @@ -4787,6 +4791,17 @@ gint main(int argc, char *argv[]) JANUS_LOG(LOG_ERR, "Invalid STUN address %s:%u. STUN will be disabled\n", stun_server, stun_port); } } + item = janus_config_get(config, config_nat, janus_config_type_item, "ice_nomination"); + if(item && item->value) { +#ifndef HAVE_ICE_NOMINATION + JANUS_LOG(LOG_WARN, "This version of libnice doesn't support setting the ICE nomination mode, ignoring '%s'\n", item->value); +#else + janus_ice_set_nomination_mode(item->value); +#endif + } + item = janus_config_get(config, config_nat, janus_config_type_item, "ice_keepalive_conncheck"); + if(item && item->value) + janus_ice_set_keepalive_conncheck_enabled(janus_is_true(item->value)); if(janus_ice_set_turn_server(turn_server, turn_port, turn_type, turn_user, turn_pwd) < 0) { if(!ignore_unreachable_ice_server) { JANUS_LOG(LOG_FATAL, "Invalid TURN address %s:%u\n", turn_server, turn_port); From d7c9ef09da1a7ebca7c5a5bbb46ee3e6e1e42aa1 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 15 Feb 2021 15:28:48 +0100 Subject: [PATCH 18/63] Added audiocodec/videocodec supporto to 'joinandconfigure' in VideoRoom API --- plugins/janus_videoroom.c | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index 9d0ad5443fc..a8f03ec30c8 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -6015,13 +6015,16 @@ static void *janus_videoroom_handler(void *data) { } /* Process the request */ json_t *audio = NULL, *video = NULL, *data = NULL, + *audiocodec = NULL, *videocodec = NULL, *bitrate = NULL, *record = NULL, *recfile = NULL, *user_audio_active_packets = NULL, *user_audio_level_average = NULL; if(!strcasecmp(request_text, "joinandconfigure")) { /* Also configure (or publish a new feed) audio/video/bitrate for this new publisher */ /* join_parameters were validated earlier. */ audio = json_object_get(root, "audio"); + audiocodec = json_object_get(root, "audiocodec"); video = json_object_get(root, "video"); + videocodec = json_object_get(root, "videocodec"); data = json_object_get(root, "data"); bitrate = json_object_get(root, "bitrate"); record = json_object_get(root, "record"); @@ -6091,11 +6094,51 @@ static void *janus_videoroom_handler(void *data) { JANUS_LOG(LOG_VERB, "Setting audio property: %s (room %s, user %s)\n", publisher->audio_active ? "true" : "false", publisher->room_id_str, publisher->user_id_str); } + if(audiocodec && json_string_value(json_object_get(msg->jsep, "sdp")) != NULL) { + /* The publisher would like to use an audio codec in particular */ + janus_audiocodec acodec = janus_audiocodec_from_name(json_string_value(audiocodec)); + if(acodec == JANUS_AUDIOCODEC_NONE || + (acodec != publisher->room->acodec[0] && + acodec != publisher->room->acodec[1] && + acodec != publisher->room->acodec[2] && + acodec != publisher->room->acodec[3] && + acodec != publisher->room->acodec[4])) { + JANUS_LOG(LOG_ERR, "Participant asked for audio codec '%s', but it's not allowed (room %s, user %s)\n", + json_string_value(audiocodec), publisher->room_id_str, publisher->user_id_str); + janus_refcount_decrease(&publisher->ref); + error_code = JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT; + g_snprintf(error_cause, 512, "Audio codec unavailable in this room"); + goto error; + } + publisher->acodec = acodec; + JANUS_LOG(LOG_VERB, "Participant asked for audio codec '%s' (room %s, user %s)\n", + json_string_value(audiocodec), publisher->room_id_str, publisher->user_id_str); + } if(video) { publisher->video_active = json_is_true(video); JANUS_LOG(LOG_VERB, "Setting video property: %s (room %s, user %s)\n", publisher->video_active ? "true" : "false", publisher->room_id_str, publisher->user_id_str); } + if(videocodec && json_string_value(json_object_get(msg->jsep, "sdp")) != NULL) { + /* The publisher would like to use a video codec in particular */ + janus_videocodec vcodec = janus_videocodec_from_name(json_string_value(videocodec)); + if(vcodec == JANUS_VIDEOCODEC_NONE || + (vcodec != publisher->room->vcodec[0] && + vcodec != publisher->room->vcodec[1] && + vcodec != publisher->room->vcodec[2] && + vcodec != publisher->room->vcodec[3] && + vcodec != publisher->room->vcodec[4])) { + JANUS_LOG(LOG_ERR, "Participant asked for video codec '%s', but it's not allowed (room %s, user %s)\n", + json_string_value(videocodec), publisher->room_id_str, publisher->user_id_str); + janus_refcount_decrease(&publisher->ref); + error_code = JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT; + g_snprintf(error_cause, 512, "Video codec unavailable in this room"); + goto error; + } + publisher->vcodec = vcodec; + JANUS_LOG(LOG_VERB, "Participant asked for video codec '%s' (room %s, user %s)\n", + json_string_value(videocodec), publisher->room_id_str, publisher->user_id_str); + } if(data) { publisher->data_active = json_is_true(data); JANUS_LOG(LOG_VERB, "Setting data property: %s (room %s, user %s)\n", From 1f45e02d5d5bb64fd163ac2d9cd7dedfd03b1bd4 Mon Sep 17 00:00:00 2001 From: Alessandro Toppi Date: Mon, 15 Feb 2021 16:38:22 +0100 Subject: [PATCH 19/63] Set specific versions for Python 3 and meson in janus-ci yml. --- .github/workflows/janus-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/janus-ci.yml b/.github/workflows/janus-ci.yml index 4806fedd79c..35b8a9561f5 100644 --- a/.github/workflows/janus-ci.yml +++ b/.github/workflows/janus-ci.yml @@ -76,11 +76,11 @@ jobs: if: ${{ matrix.deps_from_src == 'yes' }} uses: actions/setup-python@v2 with: - python-version: '3.x' + python-version: '3.8.5' architecture: 'x64' - name: install python packages if: ${{ matrix.deps_from_src == 'yes' }} - run: pip3 install wheel meson + run: pip3 install -Iv wheel meson==0.54.3 - name: setup libnice from sources if: ${{ matrix.deps_from_src == 'yes' }} run: | From d0fb6bed3b000a5dbe7394575a74462603c6d31a Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 15 Feb 2021 17:34:32 +0100 Subject: [PATCH 20/63] Add reference to publisher when using RTCP in forwarder --- plugins/janus_videoroom.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index a8f03ec30c8..2eb4e88f662 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -1571,11 +1571,17 @@ static gboolean janus_videoroom_rtp_forwarder_rtcp_dispatch(GSource *source, GSo janus_videoroom_rtp_forwarder_rtcp_receive(r->forward); return G_SOURCE_CONTINUE; } +static void janus_videoroom_publisher_dereference_void(void *p); static void janus_videoroom_rtp_forwarder_rtcp_finalize(GSource *source) { janus_videoroom_rtcp_receiver *r = (janus_videoroom_rtcp_receiver *)source; /* Remove the reference to the forwarder */ - if(r && r->forward) + if(r && r->forward) { + if(r->forward->source) { + janus_videoroom_publisher_dereference_void(r->forward->source); + r->forward->source = NULL; + } janus_refcount_decrease(&r->forward->ref); + } } static GSourceFuncs janus_videoroom_rtp_forwarder_rtcp_funcs = { janus_videoroom_rtp_forwarder_rtcp_prepare, @@ -1722,6 +1728,9 @@ static void janus_videoroom_publisher_dereference(janus_videoroom_publisher *p) /* This is used by g_pointer_clear and g_hash_table_new_full so that NULL is only possible if that was inserted into the hash table. */ janus_refcount_decrease(&p->ref); } +static void janus_videoroom_publisher_dereference_void(void *p) { + janus_videoroom_publisher_dereference((janus_videoroom_publisher *)p); +} static void janus_videoroom_publisher_dereference_by_subscriber(janus_videoroom_publisher *p) { /* This is used by g_pointer_clear and g_hash_table_new_full so that NULL is only possible if that was inserted into the hash table. */ @@ -1906,6 +1915,7 @@ static guint32 janus_videoroom_rtp_forwarder_add_helper(janus_videoroom_publishe if(!p || !host) { return 0; } + janus_refcount_increase(&p->ref); janus_mutex_lock(&p->rtp_forwarders_mutex); /* Do we need to bind to a port for RTCP? */ int fd = -1; @@ -1914,6 +1924,7 @@ static guint32 janus_videoroom_rtp_forwarder_add_helper(janus_videoroom_publishe fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if(fd < 0) { janus_mutex_unlock(&p->rtp_forwarders_mutex); + janus_refcount_decrease(&p->ref); JANUS_LOG(LOG_ERR, "Error creating RTCP socket for new RTP forwarder... %d (%s)\n", errno, strerror(errno)); return 0; @@ -1921,6 +1932,7 @@ static guint32 janus_videoroom_rtp_forwarder_add_helper(janus_videoroom_publishe int v6only = 0; if(setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) { janus_mutex_unlock(&p->rtp_forwarders_mutex); + janus_refcount_decrease(&p->ref); JANUS_LOG(LOG_ERR, "Error creating RTCP socket for new RTP forwarder... %d (%s)\n", errno, strerror(errno)); close(fd); @@ -1935,6 +1947,7 @@ static guint32 janus_videoroom_rtp_forwarder_add_helper(janus_videoroom_publishe if(bind(fd, (struct sockaddr *)&address, len) < 0 || getsockname(fd, (struct sockaddr *)&address, &len) < 0) { janus_mutex_unlock(&p->rtp_forwarders_mutex); + janus_refcount_decrease(&p->ref); JANUS_LOG(LOG_ERR, "Error binding RTCP socket for new RTP forwarder... %d (%s)\n", errno, strerror(errno)); close(fd); @@ -1975,6 +1988,7 @@ static guint32 janus_videoroom_rtp_forwarder_add_helper(janus_videoroom_publishe guchar *decoded = g_base64_decode(srtp_crypto, &len); if(len < SRTP_MASTER_LENGTH) { janus_mutex_unlock(&p->rtp_forwarders_mutex); + janus_refcount_decrease(&p->ref); JANUS_LOG(LOG_ERR, "Invalid SRTP crypto (%s)\n", srtp_crypto); g_free(decoded); g_free(srtp_ctx); @@ -1999,6 +2013,7 @@ static guint32 janus_videoroom_rtp_forwarder_add_helper(janus_videoroom_publishe if(res != srtp_err_status_ok) { /* Something went wrong... */ janus_mutex_unlock(&p->rtp_forwarders_mutex); + janus_refcount_decrease(&p->ref); JANUS_LOG(LOG_ERR, "Error creating forwarder SRTP session: %d (%s)\n", res, janus_srtp_error_str(res)); g_free(decoded); policy->key = NULL; @@ -2047,6 +2062,7 @@ static guint32 janus_videoroom_rtp_forwarder_add_helper(janus_videoroom_publishe g_hash_table_insert(p->rtp_forwarders, GUINT_TO_POINTER(stream_id), forward); if(fd > -1) { /* We need RTCP: track this file descriptor, and ref the forwarder */ + janus_refcount_increase(&p->ref); janus_refcount_increase(&forward->ref); forward->rtcp_recv = g_source_new(&janus_videoroom_rtp_forwarder_rtcp_funcs, sizeof(janus_videoroom_rtcp_receiver)); janus_videoroom_rtcp_receiver *rr = (janus_videoroom_rtcp_receiver *)forward->rtcp_recv; @@ -2079,6 +2095,7 @@ static guint32 janus_videoroom_rtp_forwarder_add_helper(janus_videoroom_publishe (void)sendto(fd, &rtp, 12, 0, address, addrlen); } janus_mutex_unlock(&p->rtp_forwarders_mutex); + janus_refcount_decrease(&p->ref); JANUS_LOG(LOG_VERB, "Added %s/%d rtp_forward to participant %s host: %s:%d stream_id: %"SCNu32"\n", is_data ? "data" : (is_video ? "video" : "audio"), substream, p->user_id_str, host, port, stream_id); return stream_id; From 6503f42de8b64ac0fa2c7c9adb1260b1b1d2fa82 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Wed, 17 Feb 2021 13:53:53 +0100 Subject: [PATCH 21/63] Fixed typo in keepalive-conncheck usage --- ice.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ice.c b/ice.c index fb1eb38a338..35b576f8df4 100644 --- a/ice.c +++ b/ice.c @@ -3499,7 +3499,7 @@ int janus_ice_setup_local(janus_ice_handle *handle, int offer, int audio, int vi #ifdef HAVE_ICE_NOMINATION "nomination-mode", janus_ice_nomination, #endif - "keepalive-conncheck", janus_ice_keepalive_connckecks ? FALSE : TRUE, + "keepalive-conncheck", janus_ice_keepalive_connckecks ? TRUE : FALSE, #ifdef HAVE_LIBNICE_TCP "ice-udp", TRUE, "ice-tcp", janus_ice_tcp_enabled ? TRUE : FALSE, From 2c81d0277f664086610d12dff4c097dc0be04acf Mon Sep 17 00:00:00 2001 From: Hritik Utekar Date: Wed, 17 Feb 2021 19:54:46 +0530 Subject: [PATCH 22/63] Video moderation always returns unmuted (#2559) --- plugins/janus_videoroom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index a8f03ec30c8..5c517dc97a4 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -4609,7 +4609,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi if(audio) json_object_set_new(event, "audio-moderation", participant->audio_muted ? json_string("muted") : json_string("unmuted")); if(video) - json_object_set_new(event, "video-moderation", participant->audio_muted ? json_string("muted") : json_string("unmuted")); + json_object_set_new(event, "video-moderation", participant->video_muted ? json_string("muted") : json_string("unmuted")); if(data) json_object_set_new(event, "data-moderation", participant->data_muted ? json_string("muted") : json_string("unmuted")); /* Notify the speaker this event is related to as well */ @@ -4624,7 +4624,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi if(audio) json_object_set_new(info, "audio", participant->audio_muted ? json_string("muted") : json_string("unmuted")); if(video) - json_object_set_new(info, "video", participant->audio_muted ? json_string("muted") : json_string("unmuted")); + json_object_set_new(info, "video", participant->video_muted ? json_string("muted") : json_string("unmuted")); if(data) json_object_set_new(info, "data", participant->data_muted ? json_string("muted") : json_string("unmuted")); gateway->notify_event(&janus_videoroom_plugin, NULL, info); From 27dc51aa0094a0b41ec8b4f99964dfcf610dbcf6 Mon Sep 17 00:00:00 2001 From: nicolasduteil Date: Wed, 17 Feb 2021 15:27:45 +0100 Subject: [PATCH 23/63] feat: add "call_id" to "calling", "declining", "updatingcall" & "incomingcall" events (#2557) --- plugins/janus_sip.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/janus_sip.c b/plugins/janus_sip.c index 492410ac3f3..aa8154118ed 100644 --- a/plugins/janus_sip.c +++ b/plugins/janus_sip.c @@ -3577,6 +3577,7 @@ static void *janus_sip_handler(void *data) { /* Send an ack back */ result = json_object(); json_object_set_new(result, "event", json_string("calling")); + json_object_set_new(result, "call_id", json_string(session->callid)); } else if(!strcasecmp(request_text, "accept")) { if(session->status != janus_sip_call_status_invited) { JANUS_LOG(LOG_ERR, "Wrong state (not invited? status=%s)\n", janus_sip_call_status_string(session->status)); @@ -4037,6 +4038,8 @@ static void *janus_sip_handler(void *data) { result = json_object(); json_object_set_new(result, "event", json_string("declining")); json_object_set_new(result, "code", json_integer(response_code)); + if(session->callid) + json_object_set_new(result, "call_id", json_string(session->callid)); } else if(!strcasecmp(request_text, "transfer")) { /* Transfer an existing call */ JANUS_VALIDATE_JSON_OBJECT(root, transfer_parameters, @@ -4924,6 +4927,8 @@ void janus_sip_sofia_callback(nua_event_t event, int status, char const *phrase, json_t *calling = json_object(); json_object_set_new(calling, "event", json_string(reinvite ? "updatingcall" : "incomingcall")); json_object_set_new(calling, "username", json_string(session->callee)); + if(session->callid) + json_object_set_new(calling, "call_id", json_string(session->callid)); if(sip->sip_from->a_display) { json_object_set_new(calling, "displayname", json_string(sip->sip_from->a_display)); } From 4f8943adf7c3292a1a4aaa08fd022c1308b9357d Mon Sep 17 00:00:00 2001 From: Tristan Matthews Date: Wed, 17 Feb 2021 09:32:57 -0500 Subject: [PATCH 24/63] ice: fix conncheck typo (#2560) No functional change since the typo was used consistently. --- ice.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ice.c b/ice.c index 35b576f8df4..99f78d4e037 100644 --- a/ice.c +++ b/ice.c @@ -124,16 +124,16 @@ const char *janus_ice_get_nomination_mode(void) { #endif /* Keepalive via connectivity checks */ -static gboolean janus_ice_keepalive_connckecks = FALSE; +static gboolean janus_ice_keepalive_connchecks = FALSE; void janus_ice_set_keepalive_conncheck_enabled(gboolean enabled) { - janus_ice_keepalive_connckecks = enabled; - if(janus_ice_keepalive_connckecks) { + janus_ice_keepalive_connchecks = enabled; + if(janus_ice_keepalive_connchecks) { JANUS_LOG(LOG_INFO, "Using connectivity checks as PeerConnection keep-alives\n"); JANUS_LOG(LOG_WARN, "Notice that the current libnice master is breaking connections after 50s when keepalive-conncheck enabled. As such, better to stick to 0.1.18 until the issue is addressed upstream\n"); } } gboolean janus_ice_is_keepalive_conncheck_enabled(void) { - return janus_ice_keepalive_connckecks; + return janus_ice_keepalive_connchecks; } /* Opaque IDs set by applications are by default only passed to event handlers @@ -3499,7 +3499,7 @@ int janus_ice_setup_local(janus_ice_handle *handle, int offer, int audio, int vi #ifdef HAVE_ICE_NOMINATION "nomination-mode", janus_ice_nomination, #endif - "keepalive-conncheck", janus_ice_keepalive_connckecks ? TRUE : FALSE, + "keepalive-conncheck", janus_ice_keepalive_connchecks ? TRUE : FALSE, #ifdef HAVE_LIBNICE_TCP "ice-udp", TRUE, "ice-tcp", janus_ice_tcp_enabled ? TRUE : FALSE, From 8246452617ea5b2c6b73e6bdea9ec9450e757719 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 22 Feb 2021 11:51:36 +0100 Subject: [PATCH 25/63] Fixed missing mutexes around VideoRoom ACL management --- plugins/janus_videoroom.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index 5c517dc97a4..d781f0fc8ef 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -4282,10 +4282,12 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi } janus_refcount_increase(&videoroom->ref); janus_mutex_unlock(&rooms_mutex); + janus_mutex_lock(&videoroom->mutex); /* A secret may be required for this action */ JANUS_CHECK_SECRET(videoroom->room_secret, root, "secret", error_code, error_cause, JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT, JANUS_VIDEOROOM_ERROR_UNAUTHORIZED); if(error_code != 0) { + janus_mutex_unlock(&videoroom->mutex); janus_refcount_decrease(&videoroom->ref); goto prepare_response; } @@ -4311,6 +4313,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi } } if(!ok) { + janus_mutex_unlock(&videoroom->mutex); JANUS_LOG(LOG_ERR, "Invalid element in the allowed array (not a string)\n"); error_code = JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT; g_snprintf(error_cause, 512, "Invalid element in the allowed array (not a string)"); @@ -4347,6 +4350,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi json_object_set_new(response, "allowed", list); } /* Done */ + janus_mutex_unlock(&videoroom->mutex); janus_refcount_decrease(&videoroom->ref); JANUS_LOG(LOG_VERB, "VideoRoom room allowed list updated\n"); goto prepare_response; From beb28be6575a3c110d10b6b5b5b15de193299183 Mon Sep 17 00:00:00 2001 From: Tvildo Date: Mon, 22 Feb 2021 09:46:25 -0800 Subject: [PATCH 26/63] add call_id in received sip message (#2563) Add call_id in received SIP MESSAGE and INFO --- plugins/janus_sip.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/janus_sip.c b/plugins/janus_sip.c index aa8154118ed..41026131d9c 100644 --- a/plugins/janus_sip.c +++ b/plugins/janus_sip.c @@ -5097,6 +5097,8 @@ void janus_sip_sofia_callback(nua_event_t event, int status, char const *phrase, json_t *headers = janus_sip_get_incoming_headers(sip, session); json_object_set_new(result, "headers", headers); } + if(session->callid) + json_object_set_new(info, "call_id", json_string(session->callid)); json_object_set_new(info, "result", result); int ret = gateway->push_event(session->handle, &janus_sip_plugin, session->transaction, info, NULL); JANUS_LOG(LOG_VERB, " >> Pushing event to peer: %d (%s)\n", ret, janus_get_api_error(ret)); @@ -5131,6 +5133,8 @@ void janus_sip_sofia_callback(nua_event_t event, int status, char const *phrase, json_t *headers = janus_sip_get_incoming_headers(sip, session); json_object_set_new(result, "headers", headers); } + if(session->callid) + json_object_set_new(message, "call_id", json_string(session->callid)); json_object_set_new(message, "result", result); int ret = gateway->push_event(session->handle, &janus_sip_plugin, session->transaction, message, NULL); JANUS_LOG(LOG_VERB, " >> Pushing event to peer: %d (%s)\n", ret, janus_get_api_error(ret)); From c9baba961165821f6c413a853bf3c1c4bb389f22 Mon Sep 17 00:00:00 2001 From: Alessandro Toppi Date: Tue, 23 Feb 2021 11:46:50 +0100 Subject: [PATCH 27/63] clang/ubsan fixes (#2556) * Fix some clang warnings. * Fix UBSanitizer error when sending RTCP SR. --- ice.c | 8 ++++---- plugins/janus_sip.c | 4 ++-- postprocessing/janus-pp-rec.c | 4 ++-- rtcp.c | 2 +- sctp.c | 2 +- transports/janus_http.c | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ice.c b/ice.c index 99f78d4e037..8180d619c71 100644 --- a/ice.c +++ b/ice.c @@ -3916,7 +3916,7 @@ static gboolean janus_ice_outgoing_rtcp_handle(gpointer user_data) { /* Create a SR/SDES compound */ int srlen = 28; int sdeslen = 16; - char rtcpbuf[srlen+sdeslen]; + char rtcpbuf[sizeof(janus_rtcp_sr)+sdeslen]; memset(rtcpbuf, 0, sizeof(rtcpbuf)); rtcp_sr *sr = (rtcp_sr *)&rtcpbuf; sr->header.version = 2; @@ -3942,7 +3942,7 @@ static gboolean janus_ice_outgoing_rtcp_handle(gpointer user_data) { } sr->si.s_packets = htonl(stream->component->out_stats.audio.packets); sr->si.s_octets = htonl(stream->component->out_stats.audio.bytes); - rtcp_sdes *sdes = (rtcp_sdes *)&rtcpbuf[28]; + rtcp_sdes *sdes = (rtcp_sdes *)&rtcpbuf[srlen]; janus_rtcp_sdes_cname((char *)sdes, sdeslen, "janus", 5); sdes->chunk.ssrc = htonl(stream->audio_ssrc); /* Enqueue it, we'll send it later */ @@ -3977,7 +3977,7 @@ static gboolean janus_ice_outgoing_rtcp_handle(gpointer user_data) { /* Create a SR/SDES compound */ int srlen = 28; int sdeslen = 16; - char rtcpbuf[srlen+sdeslen]; + char rtcpbuf[sizeof(janus_rtcp_sr)+sdeslen]; memset(rtcpbuf, 0, sizeof(rtcpbuf)); rtcp_sr *sr = (rtcp_sr *)&rtcpbuf; sr->header.version = 2; @@ -4003,7 +4003,7 @@ static gboolean janus_ice_outgoing_rtcp_handle(gpointer user_data) { } sr->si.s_packets = htonl(stream->component->out_stats.video[0].packets); sr->si.s_octets = htonl(stream->component->out_stats.video[0].bytes); - rtcp_sdes *sdes = (rtcp_sdes *)&rtcpbuf[28]; + rtcp_sdes *sdes = (rtcp_sdes *)&rtcpbuf[srlen]; janus_rtcp_sdes_cname((char *)sdes, sdeslen, "janus", 5); sdes->chunk.ssrc = htonl(stream->video_ssrc); /* Enqueue it, we'll send it later */ diff --git a/plugins/janus_sip.c b/plugins/janus_sip.c index 41026131d9c..934c97b19f8 100644 --- a/plugins/janus_sip.c +++ b/plugins/janus_sip.c @@ -4751,8 +4751,8 @@ void janus_sip_sofia_callback(nua_event_t event, int status, char const *phrase, nua_respond(nh, 500, sip_status_phrase(500), TAG_END()); break; } - if(sip->sip_from == NULL || sip->sip_from->a_url == NULL || - sip->sip_to == NULL || sip->sip_to->a_url == NULL) { + if(sip->sip_from == NULL || sip->sip_from->a_url->url_user == NULL || + sip->sip_to == NULL || sip->sip_to->a_url->url_user == NULL) { JANUS_LOG(LOG_ERR, "\tInvalid request (missing From or To)\n"); nua_respond(nh, 400, sip_status_phrase(400), TAG_END()); break; diff --git a/postprocessing/janus-pp-rec.c b/postprocessing/janus-pp-rec.c index 5ff32ae7b4b..b2c36887464 100644 --- a/postprocessing/janus-pp-rec.c +++ b/postprocessing/janus-pp-rec.c @@ -816,7 +816,7 @@ int main(int argc, char *argv[]) rtp_read_n = (rtp->csrccount + rtp->extension)*4; bytes = fread(prebuffer+rtp_header_len, sizeof(char), rtp_read_n, file); if(bytes < rtp_read_n) { - JANUS_LOG(LOG_WARN, "Missing RTP packet header data (%d instead %"SCNu16")\n", + JANUS_LOG(LOG_WARN, "Missing RTP packet header data (%d instead %d)\n", rtp_header_len+bytes, rtp_header_len+rtp_read_n); break; } else { @@ -833,7 +833,7 @@ int main(int argc, char *argv[]) skip += 4 + rtp_read_n; bytes = fread(prebuffer+rtp_header_len, sizeof(char), rtp_read_n, file); if(bytes < rtp_read_n) { - JANUS_LOG(LOG_WARN, "Missing RTP packet header data (%d instead %"SCNu16")\n", + JANUS_LOG(LOG_WARN, "Missing RTP packet header data (%d instead %d)\n", rtp_header_len+bytes, rtp_header_len+rtp_read_n); break; } else { diff --git a/rtcp.c b/rtcp.c index 4a3561ea4c4..a266fed6829 100644 --- a/rtcp.c +++ b/rtcp.c @@ -316,7 +316,7 @@ static void janus_rtcp_incoming_transport_cc(janus_rtcp_context *ctx, janus_rtcp } delta_us = delta*250; /* Print summary */ - JANUS_LOG(LOG_HUGE, " [%02"SCNu16"][%"SCNu16"] %s (%"SCNu32"us)\n", num, base_seq+num-1, + JANUS_LOG(LOG_HUGE, " [%02"SCNu16"][%"SCNu16"] %s (%"SCNu32"us)\n", num, (uint16_t)(base_seq+num-1), janus_rtp_packet_status_description(s), delta_us); iter = iter->next; } diff --git a/sctp.c b/sctp.c index 3ed4e0ae901..ec0ff77ad27 100644 --- a/sctp.c +++ b/sctp.c @@ -478,7 +478,7 @@ void janus_sctp_send_data(janus_sctp_association *sctp, char *label, char *proto int res = janus_sctp_send_text_or_binary(sctp, i, textdata, buf, len); if(res == -2) { /* Delivery failed with an EAGAIN, queue and retry later */ - JANUS_LOG(LOG_WARN, "[%"SCNu64"] Got EAGAIN when trying to send message on channel %"SCNu16", retrying later\n", + JANUS_LOG(LOG_WARN, "[%"SCNu64"] Got EAGAIN when trying to send message on channel %d, retrying later\n", sctp->handle_id, i); janus_sctp_pending_message *m = janus_sctp_pending_message_create(i, textdata, buf, len); if(sctp->pending_messages == NULL) diff --git a/transports/janus_http.c b/transports/janus_http.c index 9bed80ca508..e09f1582538 100644 --- a/transports/janus_http.c +++ b/transports/janus_http.c @@ -1051,7 +1051,7 @@ int janus_http_send_message(janus_transport_session *transport, void *request_id transport = (janus_transport_session *)session->longpolls->data; msg = (janus_http_msg *)(transport ? transport->transport_p : NULL); /* Is this connection ready to send a response back? */ - if(msg && g_atomic_pointer_compare_and_exchange(&msg->longpoll, session, NULL)) { + if(msg && g_atomic_pointer_compare_and_exchange(&msg->longpoll, (volatile void *)session, NULL)) { janus_refcount_increase(&msg->ref); /* Send the events back */ if(g_atomic_int_compare_and_exchange(&msg->timeout_flag, 1, 0)) { @@ -1176,7 +1176,7 @@ void janus_http_session_claimed(janus_transport_session *transport, guint64 sess g_source_unref(msg->timeout); } msg->timeout = NULL; - if(g_atomic_pointer_compare_and_exchange(&msg->longpoll, session, NULL)) { + if(g_atomic_pointer_compare_and_exchange(&msg->longpoll, (volatile void *)session, NULL)) { /* Return an error on the long poll right away */ janus_http_timeout(transport, old_session); } From caaba91081ba8e5578a24bca1495a8572f08e65c Mon Sep 17 00:00:00 2001 From: Tijmen de Mes Date: Tue, 23 Feb 2021 14:57:17 +0100 Subject: [PATCH 28/63] Added Content type to SIP message (#2567) * Added 'content_type' to received SIP MESSAGE * Added optional content type in sending SIP MESSAGE --- plugins/janus_sip.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/plugins/janus_sip.c b/plugins/janus_sip.c index 934c97b19f8..473075c01c6 100644 --- a/plugins/janus_sip.c +++ b/plugins/janus_sip.c @@ -411,6 +411,7 @@ \verbatim { "request" : "message", + "content_type" : "" "content" : "" } \endverbatim @@ -425,6 +426,7 @@ "event" : "message", "sender" : "", "displayname" : "", + "content_type" : "", "content" : "", "headers" : "" } @@ -798,6 +800,7 @@ static struct janus_json_parameter info_parameters[] = { {"content", JSON_STRING, JANUS_JSON_PARAM_REQUIRED} }; static struct janus_json_parameter sipmessage_parameters[] = { + {"content_type", JSON_STRING, 0}, {"content", JSON_STRING, JANUS_JSON_PARAM_REQUIRED} }; @@ -4463,7 +4466,7 @@ static void *janus_sip_handler(void *data) { result = json_object(); json_object_set_new(result, "event", json_string("infosent")); } else if(!strcasecmp(request_text, "message")) { - /* Send a SIP MESSAGE request: we'll only need the content */ + /* Send a SIP MESSAGE request: we'll only need the content and optional payload type */ if(!(session->status == janus_sip_call_status_inviting || janus_sip_call_is_established(session))) { JANUS_LOG(LOG_ERR, "Wrong state (not established? status=%s)\n", janus_sip_call_status_string(session->status)); @@ -4486,9 +4489,15 @@ static void *janus_sip_handler(void *data) { janus_mutex_unlock(&session->mutex); goto error; } + + const char *content_type = "text/plain"; + json_t *content_type_text = json_object_get(root, "content_type"); + if(content_type_text && json_is_string(content_type_text)) + content_type = json_string_value(content_type_text); + const char *msg_content = json_string_value(json_object_get(root, "content")); nua_message(session->stack->s_nh_i, - SIPTAG_CONTENT_TYPE_STR("text/plain"), + SIPTAG_CONTENT_TYPE_STR(content_type), SIPTAG_PAYLOAD_STR(msg_content), TAG_END()); /* Notify the operation */ @@ -5111,11 +5120,12 @@ void janus_sip_sofia_callback(nua_event_t event, int status, char const *phrase, case nua_i_message: { JANUS_LOG(LOG_VERB, "[%s][%s]: %d %s\n", session->account.username, nua_event_name(event), status, phrase ? phrase : "??"); /* We expect a payload */ - if(!sip->sip_payload || !sip->sip_payload->pl_data) { + if(!sip->sip_content_type || !sip->sip_content_type->c_type || !sip->sip_payload || !sip->sip_payload->pl_data) { nua_respond(nh, 488, sip_status_phrase(488), NUTAG_WITH_CURRENT(nua), TAG_END()); return; } + const char *content_type = sip->sip_content_type->c_type; char *payload = sip->sip_payload->pl_data; /* Notify the application */ json_t *message = json_object(); @@ -5135,6 +5145,7 @@ void janus_sip_sofia_callback(nua_event_t event, int status, char const *phrase, } if(session->callid) json_object_set_new(message, "call_id", json_string(session->callid)); + json_object_set_new(result, "content_type", json_string(content_type)); json_object_set_new(message, "result", result); int ret = gateway->push_event(session->handle, &janus_sip_plugin, session->transaction, message, NULL); JANUS_LOG(LOG_VERB, " >> Pushing event to peer: %d (%s)\n", ret, janus_get_api_error(ret)); From 5ac54d9f99a1d558714381e42d5addde7974bb92 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 23 Feb 2021 17:29:12 +0100 Subject: [PATCH 29/63] Make sure the publisher hasn't been destroyed, before trying to relay RTCP --- plugins/janus_videoroom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index 2eb4e88f662..9a4f3dd00ab 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -1877,7 +1877,7 @@ static void janus_videoroom_codecstr(janus_videoroom *videoroom, char *audio_cod } static void janus_videoroom_reqpli(janus_videoroom_publisher *publisher, const char *reason) { - if(publisher == NULL) + if(publisher == NULL || g_atomic_int_get(&publisher->destroyed)) return; /* Send a PLI */ JANUS_LOG(LOG_VERB, "%s sending PLI to %s (%s)\n", reason, From 905cdcc44909abe094d3b468b7d63329e4caaf31 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 23 Feb 2021 18:14:45 +0100 Subject: [PATCH 30/63] Fixed memory leak --- plugins/janus_videoroom.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index 9a4f3dd00ab..321efec8858 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -1743,8 +1743,26 @@ static void janus_videoroom_publisher_dereference_nodebug(janus_videoroom_publis } static void janus_videoroom_publisher_destroy(janus_videoroom_publisher *p) { - if(p && g_atomic_int_compare_and_exchange(&p->destroyed, 0, 1)) + if(p && g_atomic_int_compare_and_exchange(&p->destroyed, 0, 1)) { + /* Forwarders with RTCP support may have an extra reference, stop their source */ + janus_mutex_lock(&p->rtp_forwarders_mutex); + if(g_hash_table_size(p->rtp_forwarders) > 0) { + GHashTableIter iter_f; + gpointer key_f, value_f; + g_hash_table_iter_init(&iter_f, p->rtp_forwarders); + while(g_hash_table_iter_next(&iter_f, &key_f, &value_f)) { + janus_videoroom_rtp_forwarder *rpv = value_f; + if(rpv->rtcp_recv) { + GSource *source = rpv->rtcp_recv; + rpv->rtcp_recv = NULL; + g_source_destroy(source); + g_source_unref(source); + } + } + } + janus_mutex_unlock(&p->rtp_forwarders_mutex); janus_refcount_decrease(&p->ref); + } } static void janus_videoroom_publisher_free(const janus_refcount *p_ref) { @@ -2103,7 +2121,7 @@ static guint32 janus_videoroom_rtp_forwarder_add_helper(janus_videoroom_publishe static void janus_videoroom_rtp_forwarder_destroy(janus_videoroom_rtp_forwarder *forward) { if(forward && g_atomic_int_compare_and_exchange(&forward->destroyed, 0, 1)) { - if(forward->rtcp_fd > -1) { + if(forward->rtcp_fd > -1 && forward->rtcp_recv != NULL) { g_source_destroy(forward->rtcp_recv); g_source_unref(forward->rtcp_recv); } From a66a63166473b10237854456e59b1a57403bd28f Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 16 Mar 2021 12:00:50 +0100 Subject: [PATCH 31/63] Fix broken calculation of out-link-quality when NACKS exceed number of sent packets (fixes #2579) --- rtcp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rtcp.c b/rtcp.c index a266fed6829..b0455a810ad 100644 --- a/rtcp.c +++ b/rtcp.c @@ -349,6 +349,12 @@ static void janus_rtcp_rr_update_stats(rtcp_context *ctx, janus_report_block rb) uint32_t sent = g_atomic_int_get(&ctx->sent_packets_since_last_rr); uint32_t expect = ntohl(rb.ehsnr) - ctx->rr_last_ehsnr; int32_t nacks = g_atomic_int_get(&ctx->nack_count) - ctx->rr_last_nack_count; + /* In case the number of NACKs is higher than the number of sent packets, + * we normalize it and set it to the same value instead, otherwise the + * value of the out link quality will overflow: for details, see + * https://github.com/meetecho/janus-gateway/issues/2579 */ + if(sent && nacks > sent) + nacks = sent; double link_q = !sent ? 0 : 100.0 - (100.0 * nacks / (double)sent); ctx->out_link_quality = janus_rtcp_link_quality_filter(ctx->out_link_quality, link_q); int32_t lost = total_lost - ctx->rr_last_lost; From 55abe0612a981f6819af805248b0378f67898da2 Mon Sep 17 00:00:00 2001 From: Lionel Nicolas Date: Fri, 19 Mar 2021 04:14:38 -0400 Subject: [PATCH 32/63] fix rstp instead of rtsp typo (#2590) --- conf/janus.plugin.streaming.jcfg.sample.in | 2 +- plugins/janus_streaming.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/janus.plugin.streaming.jcfg.sample.in b/conf/janus.plugin.streaming.jcfg.sample.in index 7eb058bea5d..61cad00cb92 100644 --- a/conf/janus.plugin.streaming.jcfg.sample.in +++ b/conf/janus.plugin.streaming.jcfg.sample.in @@ -74,7 +74,7 @@ # DO NOT SET THIS PROPERTY IF YOU DON'T KNOW WHAT YOU'RE DOING! # e2ee = true # -# The following options are only valid for the 'rstp' type: +# The following options are only valid for the 'rtsp' type: # url = RTSP stream URL (only for restreaming RTSP) # rtsp_user = RTSP authorization username (only if type=rtsp) # rtsp_pwd = RTSP authorization password (only if type=rtsp) diff --git a/plugins/janus_streaming.c b/plugins/janus_streaming.c index 2f09777bc3a..544b614f851 100644 --- a/plugins/janus_streaming.c +++ b/plugins/janus_streaming.c @@ -134,7 +134,7 @@ so neither Janus nor the Streaming plugin have access to anything. DO NOT SET THIS PROPERTY IF YOU DON'T KNOW WHAT YOU'RE DOING! e2ee = true -The following options are only valid for the 'rstp' type: +The following options are only valid for the 'rtsp' type: url = RTSP stream URL rtsp_user = RTSP authorization username, if needed rtsp_pwd = RTSP authorization password, if needed From 20dd2db2c60a99fb89a26e2ae53750ebab66da38 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Fri, 19 Mar 2021 09:48:52 +0100 Subject: [PATCH 33/63] Changing default ICE nomination mode to 'aggressive' (see #2541) --- conf/janus.jcfg.sample.in | 2 +- ice.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/conf/janus.jcfg.sample.in b/conf/janus.jcfg.sample.in index d1a4a0b5188..83aea703dc1 100644 --- a/conf/janus.jcfg.sample.in +++ b/conf/janus.jcfg.sample.in @@ -242,7 +242,7 @@ media: { # it should work in ICE-Lite mode (by default it doesn't). If libnice is # at least 0.1.15, you can choose which ICE nomination mode to use: valid # values are "regular" and "aggressive" (the default depends on the libnice -# version itself; if we can set it, we set regular nomination). You can +# version itself; if we can set it, we set aggressive nomination). You can # also configure whether to use connectivity checks as keep-alives, which # might help detecting when a peer is no longer available (notice that # current libnice master is breaking connections after 50 seconds when diff --git a/ice.c b/ice.c index 8180d619c71..1e21e1c67c0 100644 --- a/ice.c +++ b/ice.c @@ -103,11 +103,11 @@ gboolean janus_ice_is_ipv6_enabled(void) { #ifdef HAVE_ICE_NOMINATION /* Since libnice 0.1.15, we can configure the ICE nomination mode: it was - * always "aggressive" before, we set it to "regular" by default if we can */ -static NiceNominationMode janus_ice_nomination = NICE_NOMINATION_MODE_REGULAR; + * always "aggressive" before, so we set it to "aggressive" by default as well */ +static NiceNominationMode janus_ice_nomination = NICE_NOMINATION_MODE_AGGRESSIVE; void janus_ice_set_nomination_mode(const char *nomination) { if(nomination == NULL) { - JANUS_LOG(LOG_WARN, "Invalid ICE nomination mode, falling back to 'regular'\n"); + JANUS_LOG(LOG_WARN, "Invalid ICE nomination mode, falling back to 'aggressive'\n"); } else if(!strcasecmp(nomination, "regular")) { JANUS_LOG(LOG_INFO, "Configuring Janus to use ICE regular nomination\n"); janus_ice_nomination = NICE_NOMINATION_MODE_REGULAR; @@ -115,7 +115,7 @@ void janus_ice_set_nomination_mode(const char *nomination) { JANUS_LOG(LOG_INFO, "Configuring Janus to use ICE aggressive nomination\n"); janus_ice_nomination = NICE_NOMINATION_MODE_AGGRESSIVE; } else { - JANUS_LOG(LOG_WARN, "Unsupported ICE nomination mode '%s', falling back to 'regular'\n", nomination); + JANUS_LOG(LOG_WARN, "Unsupported ICE nomination mode '%s', falling back to 'aggressive'\n", nomination); } } const char *janus_ice_get_nomination_mode(void) { From 3a5b3187044bf9721ea042c96f35a3d7ed7f7220 Mon Sep 17 00:00:00 2001 From: deep9 Date: Mon, 22 Mar 2021 11:07:40 +0100 Subject: [PATCH 34/63] Fix auth when both (token, secret) modes are enabled (#2581) --- janus.c | 2 +- transports/janus_http.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/janus.c b/janus.c index db1ca896893..03ac90daa4c 100644 --- a/janus.c +++ b/janus.c @@ -919,7 +919,7 @@ static int janus_request_check_secret(janus_request *request, guint64 session_id } } /* We consider a request authorized if either the proper API secret or a valid token has been provided */ - if(!secret_authorized && !token_authorized) + if(!(api_secret != NULL && secret_authorized) && !(janus_auth_is_enabled() && token_authorized)) return JANUS_ERROR_UNAUTHORIZED; } return 0; diff --git a/transports/janus_http.c b/transports/janus_http.c index e09f1582538..508a86c644e 100644 --- a/transports/janus_http.c +++ b/transports/janus_http.c @@ -1536,7 +1536,9 @@ static MHD_Result janus_http_handler(void *cls, struct MHD_Connection *connectio const char *secret = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "apisecret"); const char *token = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "token"); gboolean secret_authorized = FALSE, token_authorized = FALSE; - if(!gateway->is_api_secret_needed(&janus_http_transport) && !gateway->is_auth_token_needed(&janus_http_transport)) { + gboolean is_api_secret_needed = gateway->is_api_secret_needed(&janus_http_transport); + gboolean is_auth_token_needed = gateway->is_auth_token_needed(&janus_http_transport); + if(!is_api_secret_needed && !is_auth_token_needed) { /* Nothing to check */ secret_authorized = TRUE; token_authorized = TRUE; @@ -1549,8 +1551,8 @@ static MHD_Result janus_http_handler(void *cls, struct MHD_Connection *connectio /* Token is valid or disabled */ token_authorized = TRUE; } - /* We consider a request authorized if both the token and the API secret are either disabled or valid */ - if(!secret_authorized || !token_authorized) { + /* We consider a request authorized if either the proper API secret or a valid token has been provided */ + if(!(is_api_secret_needed && secret_authorized) && !(is_auth_token_needed && token_authorized)) { response = MHD_create_response_from_buffer(0, NULL, MHD_RESPMEM_PERSISTENT); janus_http_add_cors_headers(msg, response); ret = MHD_queue_response(connection, MHD_HTTP_FORBIDDEN, response); From b0974f17ff6c90d99eb49a149f56121b854039bb Mon Sep 17 00:00:00 2001 From: Tristan Matthews Date: Mon, 22 Mar 2021 06:30:14 -0400 Subject: [PATCH 35/63] errors: replace strerror with locale-safe and threadsafe g_strerror (#2565) --- config.c | 2 +- events/janus_gelfevh.c | 10 +++++----- ice.c | 6 +++--- janus.c | 2 +- log.c | 2 +- loggers/janus_jsonlog.c | 2 +- plugins/janus_audiobridge.c | 2 +- plugins/janus_duktape.c | 2 +- plugins/janus_nosip.c | 32 ++++++++++++++--------------- plugins/janus_recordplay.c | 6 +++--- plugins/janus_sip.c | 40 ++++++++++++++++++------------------- plugins/janus_streaming.c | 28 +++++++++++++------------- plugins/janus_videoroom.c | 12 +++++------ plugins/janus_voicemail.c | 2 +- postprocessing/pcap2mjr.c | 12 +++++------ record.c | 18 ++++++++--------- transports/janus_pfunix.c | 14 ++++++------- utils.c | 4 ++-- 18 files changed, 98 insertions(+), 98 deletions(-) diff --git a/config.c b/config.c index 4eb553df531..f27210cd247 100644 --- a/config.c +++ b/config.c @@ -188,7 +188,7 @@ janus_config *janus_config_parse(const char *config_file) { /* Open file */ FILE *file = fopen(config_file, "rt"); if(!file) { - JANUS_LOG(LOG_ERR, " -- Error reading configuration file '%s'... error %d (%s)\n", filename, errno, strerror(errno)); + JANUS_LOG(LOG_ERR, " -- Error reading configuration file '%s'... error %d (%s)\n", filename, errno, g_strerror(errno)); g_free(tmp_filename); return NULL; } diff --git a/events/janus_gelfevh.c b/events/janus_gelfevh.c index a3c2b8ecd38..3c243974c6a 100644 --- a/events/janus_gelfevh.c +++ b/events/janus_gelfevh.c @@ -164,14 +164,14 @@ static int janus_gelfevh_connect(void) { janus_network_address_to_string_buffer(&addr, &addr_buf) != 0) { if(res) freeaddrinfo(res); - JANUS_LOG(LOG_ERR, "Could not resolve address (%s): %d (%s)\n", backend, errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "Could not resolve address (%s): %d (%s)\n", backend, errno, g_strerror(errno)); return -1; } char *host = g_strdup(janus_network_address_string_from_buffer(&addr_buf)); freeaddrinfo(res); if((sockfd = socket(AF_INET, transport, 0)) < 0 ) { - JANUS_LOG(LOG_ERR, "Socket creation failed: %d (%s)\n", errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "Socket creation failed: %d (%s)\n", errno, g_strerror(errno)); g_free(host); return -1; } @@ -206,7 +206,7 @@ static int janus_gelfevh_send(char *message) { while(length > 0) { out_bytes = send(sockfd, buffer, length + 1, 0); if(out_bytes <= 0) { - JANUS_LOG(LOG_WARN, "Sending TCP message failed, dropping event: %d (%s)\n", errno, strerror(errno)); + JANUS_LOG(LOG_WARN, "Sending TCP message failed, dropping event: %d (%s)\n", errno, g_strerror(errno)); close(sockfd); return -1; } @@ -240,7 +240,7 @@ static int janus_gelfevh_send(char *message) { if(total == 1) { int n = send(sockfd, buf, len, 0); if(n < 0) { - JANUS_LOG(LOG_WARN, "Sending UDP message failed, dropping event: %d (%s)\n", errno, strerror(errno)); + JANUS_LOG(LOG_WARN, "Sending UDP message failed, dropping event: %d (%s)\n", errno, g_strerror(errno)); return -1; } return 0; @@ -262,7 +262,7 @@ static int janus_gelfevh_send(char *message) { buf += bytesToSend; int n = send(sockfd, head, bytesToSend + 12, 0); if(n < 0) { - JANUS_LOG(LOG_WARN, "Sending UDP message failed: %d (%s)\n", errno, strerror(errno)); + JANUS_LOG(LOG_WARN, "Sending UDP message failed: %d (%s)\n", errno, g_strerror(errno)); return -1; } offset += bytesToSend; diff --git a/ice.c b/ice.c index 1e21e1c67c0..14d992760ec 100644 --- a/ice.c +++ b/ice.c @@ -978,7 +978,7 @@ int janus_ice_test_stun_server(janus_network_address *addr, uint16_t port, addrlen = sizeof(remote6); } if(bind(fd, address, addrlen) < 0) { - JANUS_LOG(LOG_FATAL, "Bind failed for STUN BINDING test: %d (%s)\n", errno, strerror(errno)); + JANUS_LOG(LOG_FATAL, "Bind failed for STUN BINDING test: %d (%s)\n", errno, g_strerror(errno)); close(fd); return -1; } @@ -997,7 +997,7 @@ int janus_ice_test_stun_server(janus_network_address *addr, uint16_t port, timeout.tv_usec = 0; int err = select(fd+1, &readfds, NULL, NULL, &timeout); if(err < 0) { - JANUS_LOG(LOG_FATAL, "Error waiting for a response to our STUN BINDING test: %d (%s)\n", errno, strerror(errno)); + JANUS_LOG(LOG_FATAL, "Error waiting for a response to our STUN BINDING test: %d (%s)\n", errno, g_strerror(errno)); close(fd); return -1; } @@ -3576,7 +3576,7 @@ int janus_ice_setup_local(janus_ice_handle *handle, int offer, int audio, int vi char host[NI_MAXHOST]; if(getifaddrs(&ifaddr) == -1) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error getting list of interfaces... %d (%s)\n", - handle->handle_id, errno, strerror(errno)); + handle->handle_id, errno, g_strerror(errno)); } else { for(ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) { if(ifa->ifa_addr == NULL) diff --git a/janus.c b/janus.c index 03ac90daa4c..13ae5615855 100644 --- a/janus.c +++ b/janus.c @@ -4544,7 +4544,7 @@ gint main(int argc, char *argv[]) janus_network_address_string_buffer ibuf; if(getifaddrs(&ifas) == -1) { JANUS_LOG(LOG_ERR, "Unable to acquire list of network devices/interfaces; some configurations may not work as expected... %d (%s)\n", - errno, strerror(errno)); + errno, g_strerror(errno)); } else { if(janus_network_lookup_interface(ifas, item->value, &iface) != 0) { JANUS_LOG(LOG_WARN, "Error setting local IP address to %s, falling back to detecting IP address...\n", item->value); diff --git a/log.c b/log.c index f6062d145bf..e1934bb781b 100644 --- a/log.c +++ b/log.c @@ -230,7 +230,7 @@ int janus_log_init(gboolean daemon, gboolean console, const char *logfile) { /* Open a log file for writing (and append) */ janus_log_file = fopen(logfile, "awt"); if(janus_log_file == NULL) { - g_print("Error opening log file %s: %s\n", logfile, strerror(errno)); + g_print("Error opening log file %s: %s\n", logfile, g_strerror(errno)); return -1; } janus_log_filepath = g_strdup(logfile); diff --git a/loggers/janus_jsonlog.c b/loggers/janus_jsonlog.c index 07d2aafa963..94a756755bf 100644 --- a/loggers/janus_jsonlog.c +++ b/loggers/janus_jsonlog.c @@ -150,7 +150,7 @@ int janus_jsonlog_init(const char *server_name, const char *config_path) { logfile = fopen(logfilename, "a"); if(logfile == NULL) { JANUS_LOG(LOG_FATAL, "Error opening file '%s' (%d, %s)\n", - logfilename, errno, strerror(errno)); + logfilename, errno, g_strerror(errno)); } } diff --git a/plugins/janus_audiobridge.c b/plugins/janus_audiobridge.c index d922024266c..f92c5d4a3f1 100644 --- a/plugins/janus_audiobridge.c +++ b/plugins/janus_audiobridge.c @@ -6848,7 +6848,7 @@ static void *janus_audiobridge_mixer_thread(void *data) { size_t addrlen = (forwarder->serv_addr.sin_family == AF_INET ? sizeof(forwarder->serv_addr) : sizeof(forwarder->serv_addr6)); if(sendto(audiobridge->rtp_udp_sock, payload, plen, 0, address, addrlen) < 0) { JANUS_LOG(LOG_HUGE, "Error forwarding mixed RTP packet for room %s... %s (len=%d)...\n", - audiobridge->room_id_str, strerror(errno), plen); + audiobridge->room_id_str, g_strerror(errno), plen); } } } diff --git a/plugins/janus_duktape.c b/plugins/janus_duktape.c index 497a68f9654..b5776fc69c9 100644 --- a/plugins/janus_duktape.c +++ b/plugins/janus_duktape.c @@ -461,7 +461,7 @@ static duk_ret_t janus_duktape_method_readfile(duk_context *ctx) { fseek(f, 0, SEEK_END); int len = (int)ftell(f); if(len < 0) { - duk_push_error_object(ctx, DUK_ERR_ERROR, "Error opening file: %s\n", strerror(errno)); + duk_push_error_object(ctx, DUK_ERR_ERROR, "Error opening file: %s\n", g_strerror(errno)); return duk_throw(ctx); } fseek(f, 0, SEEK_SET); diff --git a/plugins/janus_nosip.c b/plugins/janus_nosip.c index 556904c09f9..257f5dda1e7 100644 --- a/plugins/janus_nosip.c +++ b/plugins/janus_nosip.c @@ -688,7 +688,7 @@ int janus_nosip_init(janus_callbacks *callback, const char *config_path) { janus_network_address_string_buffer ibuf; if(getifaddrs(&ifas) == -1) { JANUS_LOG(LOG_ERR, "Unable to acquire list of network devices/interfaces; some configurations may not work as expected... %d (%s)\n", - errno, strerror(errno)); + errno, g_strerror(errno)); } else { if(janus_network_lookup_interface(ifas, item->value, &iface) != 0) { JANUS_LOG(LOG_WARN, "Error setting local IP address to %s, falling back to detecting IP address...\n", item->value); @@ -1106,7 +1106,7 @@ void janus_nosip_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp *pa guint32 timestamp = ntohl(header->timestamp); guint16 seq = ntohs(header->seq_number); JANUS_LOG(LOG_HUGE, "[NoSIP-%p] Error sending %s SRTP packet... %s (len=%d, ts=%"SCNu32", seq=%"SCNu16")...\n", - session, video ? "Video" : "Audio", strerror(errno), protected, timestamp, seq); + session, video ? "Video" : "Audio", g_strerror(errno), protected, timestamp, seq); } } } else { @@ -1116,7 +1116,7 @@ void janus_nosip_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp *pa guint32 timestamp = ntohl(header->timestamp); guint16 seq = ntohs(header->seq_number); JANUS_LOG(LOG_HUGE, "[NoSIP-%p] Error sending %s RTP packet... %s (len=%d, ts=%"SCNu32", seq=%"SCNu16")...\n", - session, video ? "Video" : "Audio", strerror(errno), len, timestamp, seq); + session, video ? "Video" : "Audio", g_strerror(errno), len, timestamp, seq); } } } @@ -1162,14 +1162,14 @@ void janus_nosip_incoming_rtcp(janus_plugin_session *handle, janus_plugin_rtcp * /* Forward the message to the peer */ if(send((video ? session->media.video_rtcp_fd : session->media.audio_rtcp_fd), sbuf, protected, 0) < 0) { JANUS_LOG(LOG_HUGE, "[NoSIP-%p] Error sending SRTCP %s packet... %s (len=%d)...\n", - session, video ? "Video" : "Audio", strerror(errno), protected); + session, video ? "Video" : "Audio", g_strerror(errno), protected); } } } else { /* Forward the message to the peer */ if(send((video ? session->media.video_rtcp_fd : session->media.audio_rtcp_fd), buf, len, 0) < 0) { JANUS_LOG(LOG_HUGE, "[NoSIP-%p] Error sending RTCP %s packet... %s (len=%d)...\n", - session, video ? "Video" : "Audio", strerror(errno), len); + session, video ? "Video" : "Audio", g_strerror(errno), len); } } } @@ -1965,14 +1965,14 @@ static int janus_nosip_allocate_port_pair(gboolean video, int fds[2], int ports[ int ret = setsockopt(rtp_fd, IPPROTO_IP, IP_TOS, &optval, sizeof(optval)); if(ret < 0) { JANUS_LOG(LOG_WARN, "Error setting IP_TOS %d on audio RTP socket (error=%s)\n", - optval, strerror(errno)); + optval, g_strerror(errno)); } } else if(rtp_fd != -1 && video && dscp_video_rtp > 0) { int optval = dscp_video_rtp << 2; int ret = setsockopt(rtp_fd, IPPROTO_IP, IP_TOS, &optval, sizeof(optval)); if(ret < 0) { JANUS_LOG(LOG_WARN, "Error setting IP_TOS %d on video RTP socket (error=%s)\n", - optval, strerror(errno)); + optval, g_strerror(errno)); } } } @@ -2134,28 +2134,28 @@ static void janus_nosip_connect_sockets(janus_nosip_session *session, struct soc audio_server_addr->sin_port = htons(session->media.remote_audio_rtp_port); if(connect(session->media.audio_rtp_fd, (struct sockaddr *)audio_server_addr, sizeof(struct sockaddr)) == -1) { JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't connect audio RTP? (%s:%d)\n", session, session->media.remote_audio_ip, session->media.remote_audio_rtp_port); - JANUS_LOG(LOG_ERR, "[NoSIP-%p] -- %d (%s)\n", session, errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "[NoSIP-%p] -- %d (%s)\n", session, errno, g_strerror(errno)); } } if(session->media.remote_audio_rtcp_port && audio_server_addr && session->media.audio_rtcp_fd != -1) { audio_server_addr->sin_port = htons(session->media.remote_audio_rtcp_port); if(connect(session->media.audio_rtcp_fd, (struct sockaddr *)audio_server_addr, sizeof(struct sockaddr)) == -1) { JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't connect audio RTCP? (%s:%d)\n", session, session->media.remote_audio_ip, session->media.remote_audio_rtcp_port); - JANUS_LOG(LOG_ERR, "[NoSIP-%p] -- %d (%s)\n", session, errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "[NoSIP-%p] -- %d (%s)\n", session, errno, g_strerror(errno)); } } if(session->media.remote_video_rtp_port && video_server_addr && session->media.video_rtp_fd != -1) { video_server_addr->sin_port = htons(session->media.remote_video_rtp_port); if(connect(session->media.video_rtp_fd, (struct sockaddr *)video_server_addr, sizeof(struct sockaddr)) == -1) { JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't connect video RTP? (%s:%d)\n", session, session->media.remote_video_ip, session->media.remote_video_rtp_port); - JANUS_LOG(LOG_ERR, "[NoSIP-%p] -- %d (%s)\n", session, errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "[NoSIP-%p] -- %d (%s)\n", session, errno, g_strerror(errno)); } } if(session->media.remote_video_rtcp_port && video_server_addr && session->media.video_rtcp_fd != -1) { video_server_addr->sin_port = htons(session->media.remote_video_rtcp_port); if(connect(session->media.video_rtcp_fd, (struct sockaddr *)video_server_addr, sizeof(struct sockaddr)) == -1) { JANUS_LOG(LOG_ERR, "[NoSIP-%p] Couldn't connect video RTCP? (%s:%d)\n", session, session->media.remote_video_ip, session->media.remote_video_rtcp_port); - JANUS_LOG(LOG_ERR, "[NoSIP-%p] -- %d (%s)\n", session, errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "[NoSIP-%p] -- %d (%s)\n", session, errno, g_strerror(errno)); } } @@ -2321,11 +2321,11 @@ static void *janus_nosip_relay_thread(void *data) { resfd = poll(fds, num, 1000); if(resfd < 0) { if(errno == EINTR) { - JANUS_LOG(LOG_HUGE, "[NoSIP-%p] Got an EINTR (%s), ignoring...\n", session, strerror(errno)); + JANUS_LOG(LOG_HUGE, "[NoSIP-%p] Got an EINTR (%s), ignoring...\n", session, g_strerror(errno)); continue; } JANUS_LOG(LOG_ERR, "[NoSIP-%p] Error polling...\n", session); - JANUS_LOG(LOG_ERR, "[NoSIP-%p] -- %d (%s)\n", session, errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "[NoSIP-%p] -- %d (%s)\n", session, errno, g_strerror(errno)); break; } else if(resfd == 0) { /* No data, keep going */ @@ -2350,12 +2350,12 @@ static void *janus_nosip_relay_thread(void *data) { /* ICMP error? If it's related to RTCP, let's just close the RTCP socket and move on */ if(fds[i].fd == session->media.audio_rtcp_fd) { JANUS_LOG(LOG_WARN, "[NoSIP-%p] Got a '%s' on the audio RTCP socket, closing it\n", - session, strerror(error)); + session, g_strerror(error)); close(session->media.audio_rtcp_fd); session->media.audio_rtcp_fd = -1; } else if(fds[i].fd == session->media.video_rtcp_fd) { JANUS_LOG(LOG_WARN, "[NoSIP-%p] Got a '%s' on the video RTCP socket, closing it\n", - session, strerror(error)); + session, g_strerror(error)); close(session->media.video_rtcp_fd); session->media.video_rtcp_fd = -1; } @@ -2366,7 +2366,7 @@ static void *janus_nosip_relay_thread(void *data) { continue; JANUS_LOG(LOG_ERR, "[NoSIP-%p] Too many errors polling %d (socket #%d): %s...\n", session, fds[i].fd, i, fds[i].revents & POLLERR ? "POLLERR" : "POLLHUP"); - JANUS_LOG(LOG_ERR, "[NoSIP-%p] -- %d (%s)\n", session, error, strerror(error)); + JANUS_LOG(LOG_ERR, "[NoSIP-%p] -- %d (%s)\n", session, error, g_strerror(error)); /* Can we assume it's pretty much over, after a POLLERR? */ goon = FALSE; /* FIXME Close the PeerConnection */ diff --git a/plugins/janus_recordplay.c b/plugins/janus_recordplay.c index 2427d7afe95..1433fe160af 100644 --- a/plugins/janus_recordplay.c +++ b/plugins/janus_recordplay.c @@ -580,7 +580,7 @@ static const char *janus_recordplay_parse_codec(const char *dir, const char *fil /* This is the info header */ bytes = fread(prebuffer, sizeof(char), len, file); if(bytes < 0) { - JANUS_LOG(LOG_ERR, "Error reading from file... %s\n", strerror(errno)); + JANUS_LOG(LOG_ERR, "Error reading from file... %s\n", g_strerror(errno)); fclose(file); return NULL; } @@ -814,7 +814,7 @@ int janus_recordplay_init(janus_callbacks *callback, const char *config_path) { int res = janus_mkdir(recordings_path, 0755); JANUS_LOG(LOG_VERB, "Creating folder: %d\n", res); if(res != 0) { - JANUS_LOG(LOG_ERR, "%s", strerror(errno)); + JANUS_LOG(LOG_ERR, "%s", g_strerror(errno)); return -1; /* No point going on... */ } } @@ -2317,7 +2317,7 @@ janus_recordplay_frame_packet *janus_recordplay_get_frames(const char *dir, cons JANUS_LOG(LOG_VERB, "New .mjr header format\n"); bytes = fread(prebuffer, sizeof(char), len, file); if(bytes < 0) { - JANUS_LOG(LOG_ERR, "Error reading from file... %s\n", strerror(errno)); + JANUS_LOG(LOG_ERR, "Error reading from file... %s\n", g_strerror(errno)); fclose(file); return NULL; } diff --git a/plugins/janus_sip.c b/plugins/janus_sip.c index 473075c01c6..a1c0d3c98ef 100644 --- a/plugins/janus_sip.c +++ b/plugins/janus_sip.c @@ -1766,7 +1766,7 @@ int janus_sip_init(janus_callbacks *callback, const char *config_path) { janus_network_address_string_buffer ibuf; if(getifaddrs(&ifas) == -1) { JANUS_LOG(LOG_ERR, "Unable to acquire list of network devices/interfaces; some configurations may not work as expected... %d (%s)\n", - errno, strerror(errno)); + errno, g_strerror(errno)); } else { if(janus_network_lookup_interface(ifas, item->value, &iface) != 0) { JANUS_LOG(LOG_WARN, "Error setting local IP address to %s, falling back to detecting IP address...\n", item->value); @@ -2338,7 +2338,7 @@ void janus_sip_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp *pack guint32 timestamp = ntohl(header->timestamp); guint16 seq = ntohs(header->seq_number); JANUS_LOG(LOG_HUGE, "[SIP-%s] Error sending SRTP video packet... %s (len=%d, ts=%"SCNu32", seq=%"SCNu16")...\n", - session->account.username, strerror(errno), protected, timestamp, seq); + session->account.username, g_strerror(errno), protected, timestamp, seq); } } } else { @@ -2348,7 +2348,7 @@ void janus_sip_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp *pack guint32 timestamp = ntohl(header->timestamp); guint16 seq = ntohs(header->seq_number); JANUS_LOG(LOG_HUGE, "[SIP-%s] Error sending RTP video packet... %s (len=%d, ts=%"SCNu32", seq=%"SCNu16")...\n", - session->account.username, strerror(errno), len, timestamp, seq); + session->account.username, g_strerror(errno), len, timestamp, seq); } } } @@ -2384,7 +2384,7 @@ void janus_sip_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp *pack guint32 timestamp = ntohl(header->timestamp); guint16 seq = ntohs(header->seq_number); JANUS_LOG(LOG_HUGE, "[SIP-%s] Error sending SRTP audio packet... %s (len=%d, ts=%"SCNu32", seq=%"SCNu16")...\n", - session->account.username, strerror(errno), protected, timestamp, seq); + session->account.username, g_strerror(errno), protected, timestamp, seq); } } } else { @@ -2394,7 +2394,7 @@ void janus_sip_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp *pack guint32 timestamp = ntohl(header->timestamp); guint16 seq = ntohs(header->seq_number); JANUS_LOG(LOG_HUGE, "[SIP-%s] Error sending RTP audio packet... %s (len=%d, ts=%"SCNu32", seq=%"SCNu16")...\n", - session->account.username, strerror(errno), len, timestamp, seq); + session->account.username, g_strerror(errno), len, timestamp, seq); } } } @@ -2436,14 +2436,14 @@ void janus_sip_incoming_rtcp(janus_plugin_session *handle, janus_plugin_rtcp *pa /* Forward the message to the peer */ if(send(session->media.video_rtcp_fd, sbuf, protected, 0) < 0) { JANUS_LOG(LOG_HUGE, "[SIP-%s] Error sending SRTCP video packet... %s (len=%d)...\n", - session->account.username, strerror(errno), protected); + session->account.username, g_strerror(errno), protected); } } } else { /* Forward the message to the peer */ if(send(session->media.video_rtcp_fd, buf, len, 0) < 0) { JANUS_LOG(LOG_HUGE, "[SIP-%s] Error sending RTCP video packet... %s (len=%d)...\n", - session->account.username, strerror(errno), len); + session->account.username, g_strerror(errno), len); } } } @@ -2466,14 +2466,14 @@ void janus_sip_incoming_rtcp(janus_plugin_session *handle, janus_plugin_rtcp *pa /* Forward the message to the peer */ if(send(session->media.audio_rtcp_fd, sbuf, protected, 0) < 0) { JANUS_LOG(LOG_HUGE, "[SIP-%s] Error sending SRTCP audio packet... %s (len=%d)...\n", - session->account.username, strerror(errno), protected); + session->account.username, g_strerror(errno), protected); } } } else { /* Forward the message to the peer */ if(send(session->media.audio_rtcp_fd, buf, len, 0) < 0) { JANUS_LOG(LOG_HUGE, "[SIP-%s] Error sending RTCP audio packet... %s (len=%d)...\n", - session->account.username, strerror(errno), len); + session->account.username, g_strerror(errno), len); } } } @@ -6093,7 +6093,7 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u int ret = setsockopt(session->media.audio_rtp_fd, IPPROTO_IP, IP_TOS, &optval, sizeof(optval)); if(ret < 0) { JANUS_LOG(LOG_WARN, "Error setting IP_TOS %d on audio RTP socket (error=%s)\n", - optval, strerror(errno)); + optval, g_strerror(errno)); } } } @@ -6151,7 +6151,7 @@ static int janus_sip_allocate_local_ports(janus_sip_session *session, gboolean u int ret = setsockopt(session->media.video_rtp_fd, IPPROTO_IP, IP_TOS, &optval, sizeof(optval)); if(ret < 0) { JANUS_LOG(LOG_WARN, "Error setting IP_TOS %d on video RTP socket (error=%s)\n", - optval, strerror(errno)); + optval, g_strerror(errno)); } } } @@ -6210,28 +6210,28 @@ static void janus_sip_connect_sockets(janus_sip_session *session, struct sockadd audio_server_addr->sin_port = htons(session->media.remote_audio_rtp_port); if(connect(session->media.audio_rtp_fd, (struct sockaddr *)audio_server_addr, sizeof(struct sockaddr)) == -1) { JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect audio RTP? (%s:%d)\n", session->account.username, session->media.remote_audio_ip, session->media.remote_audio_rtp_port); - JANUS_LOG(LOG_ERR, "[SIP-%s] -- %d (%s)\n", session->account.username, errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "[SIP-%s] -- %d (%s)\n", session->account.username, errno, g_strerror(errno)); } } if(session->media.remote_audio_rtcp_port && audio_server_addr && session->media.audio_rtcp_fd != -1) { audio_server_addr->sin_port = htons(session->media.remote_audio_rtcp_port); if(connect(session->media.audio_rtcp_fd, (struct sockaddr *)audio_server_addr, sizeof(struct sockaddr)) == -1) { JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect audio RTCP? (%s:%d)\n", session->account.username, session->media.remote_audio_ip, session->media.remote_audio_rtcp_port); - JANUS_LOG(LOG_ERR, "[SIP-%s] -- %d (%s)\n", session->account.username, errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "[SIP-%s] -- %d (%s)\n", session->account.username, errno, g_strerror(errno)); } } if(session->media.remote_video_rtp_port && video_server_addr && session->media.video_rtp_fd != -1) { video_server_addr->sin_port = htons(session->media.remote_video_rtp_port); if(connect(session->media.video_rtp_fd, (struct sockaddr *)video_server_addr, sizeof(struct sockaddr)) == -1) { JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect video RTP? (%s:%d)\n", session->account.username, session->media.remote_video_ip, session->media.remote_video_rtp_port); - JANUS_LOG(LOG_ERR, "[SIP-%s] -- %d (%s)\n", session->account.username, errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "[SIP-%s] -- %d (%s)\n", session->account.username, errno, g_strerror(errno)); } } if(session->media.remote_video_rtcp_port && video_server_addr && session->media.video_rtcp_fd != -1) { video_server_addr->sin_port = htons(session->media.remote_video_rtcp_port); if(connect(session->media.video_rtcp_fd, (struct sockaddr *)video_server_addr, sizeof(struct sockaddr)) == -1) { JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect video RTCP? (%s:%d)\n", session->account.username, session->media.remote_video_ip, session->media.remote_video_rtcp_port); - JANUS_LOG(LOG_ERR, "[SIP-%s] -- %d (%s)\n", session->account.username, errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "[SIP-%s] -- %d (%s)\n", session->account.username, errno, g_strerror(errno)); } } } @@ -6415,11 +6415,11 @@ static void *janus_sip_relay_thread(void *data) { resfd = poll(fds, num, 1000); if(resfd < 0) { if(errno == EINTR) { - JANUS_LOG(LOG_HUGE, "[SIP-%s] Got an EINTR (%s), ignoring...\n", session->account.username, strerror(errno)); + JANUS_LOG(LOG_HUGE, "[SIP-%s] Got an EINTR (%s), ignoring...\n", session->account.username, g_strerror(errno)); continue; } JANUS_LOG(LOG_ERR, "[SIP-%s] Error polling...\n", session->account.username); - JANUS_LOG(LOG_ERR, "[SIP-%s] -- %d (%s)\n", session->account.username, errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "[SIP-%s] -- %d (%s)\n", session->account.username, errno, g_strerror(errno)); break; } else if(resfd == 0) { /* No data, keep going */ @@ -6446,13 +6446,13 @@ static void *janus_sip_relay_thread(void *data) { /* ICMP error? If it's related to RTCP, let's just close the RTCP socket and move on */ if(fds[i].fd == session->media.audio_rtcp_fd) { JANUS_LOG(LOG_WARN, "[SIP-%s] Got a '%s' on the audio RTCP socket, closing it\n", - session->account.username, strerror(error)); + session->account.username, g_strerror(error)); close(session->media.audio_rtcp_fd); session->media.audio_rtcp_fd = -1; continue; } else if(fds[i].fd == session->media.video_rtcp_fd) { JANUS_LOG(LOG_WARN, "[SIP-%s] Got a '%s' on the video RTCP socket, closing it\n", - session->account.username, strerror(error)); + session->account.username, g_strerror(error)); close(session->media.video_rtcp_fd); session->media.video_rtcp_fd = -1; continue; @@ -6464,7 +6464,7 @@ static void *janus_sip_relay_thread(void *data) { continue; JANUS_LOG(LOG_ERR, "[SIP-%s] Too many errors polling %d (socket #%d): %s...\n", session->account.username, fds[i].fd, i, fds[i].revents & POLLERR ? "POLLERR" : "POLLHUP"); - JANUS_LOG(LOG_ERR, "[SIP-%s] -- %d (%s)\n", session->account.username, error, strerror(error)); + JANUS_LOG(LOG_ERR, "[SIP-%s] -- %d (%s)\n", session->account.username, error, g_strerror(error)); goon = FALSE; /* Can we assume it's pretty much over, after a POLLERR? */ /* FIXME Simulate a "hangup" coming from the application */ janus_sip_hangup_media(session->handle); diff --git a/plugins/janus_streaming.c b/plugins/janus_streaming.c index 544b614f851..8f76e7fec7a 100644 --- a/plugins/janus_streaming.c +++ b/plugins/janus_streaming.c @@ -1507,7 +1507,7 @@ static void janus_streaming_rtcp_pli_send(janus_streaming_rtp_source *source) { int sent = 0; if((sent = sendto(source->video_rtcp_fd, rtcp_buf, rtcp_len, 0, (struct sockaddr *)&source->video_rtcp_addr, sizeof(source->video_rtcp_addr))) < 0) { - JANUS_LOG(LOG_ERR, "Error in sendto... %d (%s)\n", errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "Error in sendto... %d (%s)\n", errno, g_strerror(errno)); } else { JANUS_LOG(LOG_HUGE, "Sent %d/%d bytes\n", sent, rtcp_len); } @@ -1532,7 +1532,7 @@ static void janus_streaming_rtcp_remb_send(janus_streaming_rtp_source *source) { int sent = 0; if((sent = sendto(source->video_rtcp_fd, rtcp_buf, rtcp_len, 0, (struct sockaddr *)&source->video_rtcp_addr, sizeof(source->video_rtcp_addr))) < 0) { - JANUS_LOG(LOG_ERR, "Error in sendto... %d (%s)\n", errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "Error in sendto... %d (%s)\n", errno, g_strerror(errno)); } else { JANUS_LOG(LOG_HUGE, "Sent %d/%d bytes\n", sent, rtcp_len); } @@ -1576,7 +1576,7 @@ int janus_streaming_init(janus_callbacks *callback, const char *config_path) { struct ifaddrs *ifas = NULL; if(getifaddrs(&ifas) == -1) { JANUS_LOG(LOG_ERR, "Unable to acquire list of network devices/interfaces; some configurations may not work as expected... %d (%s)\n", - errno, strerror(errno)); + errno, g_strerror(errno)); } /* Read configuration */ @@ -2661,7 +2661,7 @@ static json_t *janus_streaming_process_synchronous_request(janus_streaming_sessi if(getifaddrs(&ifas) == -1) { JANUS_LOG(LOG_ERR, "Unable to acquire list of network devices/interfaces; some configurations may not work as expected... %d (%s)\n", - errno, strerror(errno)); + errno, g_strerror(errno)); } json_t *type = json_object_get(root, "type"); @@ -5416,14 +5416,14 @@ static int janus_streaming_create_fd(int port, in_addr_t mcast, const janus_netw fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(fd < 0) { JANUS_LOG(LOG_ERR, "[%s] Cannot create socket for %s... %d (%s)\n", - mountpointname, medianame, errno, strerror(errno)); + mountpointname, medianame, errno, g_strerror(errno)); break; } #ifdef IP_MULTICAST_ALL int mc_all = 0; if((setsockopt(fd, IPPROTO_IP, IP_MULTICAST_ALL, (void*) &mc_all, sizeof(mc_all))) < 0) { JANUS_LOG(LOG_ERR, "[%s] %s listener setsockopt IP_MULTICAST_ALL failed... %d (%s)\n", - mountpointname, listenername, errno, strerror(errno)); + mountpointname, listenername, errno, g_strerror(errno)); close(fd); janus_mutex_unlock(&fd_mutex); return -1; @@ -5453,7 +5453,7 @@ static int janus_streaming_create_fd(int port, in_addr_t mcast, const janus_netw } if(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == -1) { JANUS_LOG(LOG_ERR, "[%s] %s listener IP_ADD_MEMBERSHIP failed... %d (%s)\n", - mountpointname, listenername, errno, strerror(errno)); + mountpointname, listenername, errno, g_strerror(errno)); close(fd); janus_mutex_unlock(&fd_mutex); return -1; @@ -5481,7 +5481,7 @@ static int janus_streaming_create_fd(int port, in_addr_t mcast, const janus_netw int reuse = 1; if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) { JANUS_LOG(LOG_ERR, "[%s] %s listener setsockopt SO_REUSEADDR failed... %d (%s)\n", - mountpointname, listenername, errno, strerror(errno)); + mountpointname, listenername, errno, g_strerror(errno)); close(fd); janus_mutex_unlock(&fd_mutex); return -1; @@ -5518,12 +5518,12 @@ static int janus_streaming_create_fd(int port, in_addr_t mcast, const janus_netw int v6only = 0; if(fd < 0) { JANUS_LOG(LOG_ERR, "[%s] Cannot create socket for %s... %d (%s)\n", - mountpointname, medianame, errno, strerror(errno)); + mountpointname, medianame, errno, g_strerror(errno)); break; } if(family != AF_INET && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) { JANUS_LOG(LOG_ERR, "[%s] setsockopt on socket failed for %s... %d (%s)\n", - mountpointname, medianame, errno, strerror(errno)); + mountpointname, medianame, errno, g_strerror(errno)); break; } } @@ -5533,7 +5533,7 @@ static int janus_streaming_create_fd(int port, in_addr_t mcast, const janus_netw fd = -1; if(!quiet) { JANUS_LOG(LOG_ERR, "[%s] Bind failed for %s (port %d)... %d (%s)\n", - mountpointname, medianame, port, errno, strerror(errno)); + mountpointname, medianame, port, errno, g_strerror(errno)); } if(!use_range) /* Asked for a specific port but it's not available, give up */ break; @@ -7681,10 +7681,10 @@ static void *janus_streaming_relay_thread(void *data) { resfd = poll(fds, num, 1000); if(resfd < 0) { if(errno == EINTR) { - JANUS_LOG(LOG_HUGE, "[%s] Got an EINTR (%s), ignoring...\n", name, strerror(errno)); + JANUS_LOG(LOG_HUGE, "[%s] Got an EINTR (%s), ignoring...\n", name, g_strerror(errno)); continue; } - JANUS_LOG(LOG_ERR, "[%s] Error polling... %d (%s)\n", name, errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "[%s] Error polling... %d (%s)\n", name, errno, g_strerror(errno)); mountpoint->enabled = FALSE; janus_mutex_lock(&source->rec_mutex); if(source->arc) { @@ -7719,7 +7719,7 @@ static void *janus_streaming_relay_thread(void *data) { if(fds[i].revents & (POLLERR | POLLHUP)) { /* Socket error? */ JANUS_LOG(LOG_ERR, "[%s] Error polling: %s... %d (%s)\n", name, - fds[i].revents & POLLERR ? "POLLERR" : "POLLHUP", errno, strerror(errno)); + fds[i].revents & POLLERR ? "POLLERR" : "POLLHUP", errno, g_strerror(errno)); mountpoint->enabled = FALSE; janus_mutex_lock(&source->rec_mutex); if(source->arc) { diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index 13d3d6fb63b..56852477aa2 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -1944,7 +1944,7 @@ static guint32 janus_videoroom_rtp_forwarder_add_helper(janus_videoroom_publishe janus_mutex_unlock(&p->rtp_forwarders_mutex); janus_refcount_decrease(&p->ref); JANUS_LOG(LOG_ERR, "Error creating RTCP socket for new RTP forwarder... %d (%s)\n", - errno, strerror(errno)); + errno, g_strerror(errno)); return 0; } int v6only = 0; @@ -1952,7 +1952,7 @@ static guint32 janus_videoroom_rtp_forwarder_add_helper(janus_videoroom_publishe janus_mutex_unlock(&p->rtp_forwarders_mutex); janus_refcount_decrease(&p->ref); JANUS_LOG(LOG_ERR, "Error creating RTCP socket for new RTP forwarder... %d (%s)\n", - errno, strerror(errno)); + errno, g_strerror(errno)); close(fd); return 0; } @@ -1967,7 +1967,7 @@ static guint32 janus_videoroom_rtp_forwarder_add_helper(janus_videoroom_publishe janus_mutex_unlock(&p->rtp_forwarders_mutex); janus_refcount_decrease(&p->ref); JANUS_LOG(LOG_ERR, "Error binding RTCP socket for new RTP forwarder... %d (%s)\n", - errno, strerror(errno)); + errno, g_strerror(errno)); close(fd); return 0; } @@ -5291,7 +5291,7 @@ void janus_videoroom_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp size_t addrlen = (rtp_forward->serv_addr.sin_family == AF_INET ? sizeof(rtp_forward->serv_addr) : sizeof(rtp_forward->serv_addr6)); if(sendto(participant->udp_sock, buf, len, 0, address, addrlen) < 0) { JANUS_LOG(LOG_HUGE, "Error forwarding RTP %s packet for %s... %s (len=%d)...\n", - (video ? "video" : "audio"), participant->display, strerror(errno), len); + (video ? "video" : "audio"), participant->display, g_strerror(errno), len); } } else { /* SRTP: check if we already encrypted the packet before */ @@ -5315,7 +5315,7 @@ void janus_videoroom_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp size_t addrlen = (rtp_forward->serv_addr.sin_family == AF_INET ? sizeof(rtp_forward->serv_addr) : sizeof(rtp_forward->serv_addr6)); if(sendto(participant->udp_sock, rtp_forward->srtp_ctx->sbuf, rtp_forward->srtp_ctx->slen, 0, address, addrlen) < 0) { JANUS_LOG(LOG_HUGE, "Error forwarding SRTP %s packet for %s... %s (len=%d)...\n", - (video ? "video" : "audio"), participant->display, strerror(errno), rtp_forward->srtp_ctx->slen); + (video ? "video" : "audio"), participant->display, g_strerror(errno), rtp_forward->srtp_ctx->slen); } } } @@ -5505,7 +5505,7 @@ void janus_videoroom_incoming_data(janus_plugin_session *handle, janus_plugin_da size_t addrlen = (rtp_forward->serv_addr.sin_family == AF_INET ? sizeof(rtp_forward->serv_addr) : sizeof(rtp_forward->serv_addr6)); if(sendto(participant->udp_sock, buf, len, 0, address, addrlen) < 0) { JANUS_LOG(LOG_HUGE, "Error forwarding data packet for %s... %s (len=%d)...\n", - participant->display, strerror(errno), len); + participant->display, g_strerror(errno), len); } } } diff --git a/plugins/janus_voicemail.c b/plugins/janus_voicemail.c index 8f337976c80..5c5eb03c2f6 100644 --- a/plugins/janus_voicemail.c +++ b/plugins/janus_voicemail.c @@ -352,7 +352,7 @@ int janus_voicemail_init(janus_callbacks *callback, const char *config_path) { int res = janus_mkdir(recordings_path, 0755); JANUS_LOG(LOG_VERB, "Creating folder: %d\n", res); if(res != 0) { - JANUS_LOG(LOG_ERR, "%s", strerror(errno)); + JANUS_LOG(LOG_ERR, "%s", g_strerror(errno)); return -1; /* No point going on... */ } } diff --git a/postprocessing/pcap2mjr.c b/postprocessing/pcap2mjr.c index 0e7362c7ed9..e3bdd9bebcc 100644 --- a/postprocessing/pcap2mjr.c +++ b/postprocessing/pcap2mjr.c @@ -171,7 +171,7 @@ int main(int argc, char *argv[]) size_t res = fwrite(header, sizeof(char), strlen(header), outfile); if(res != strlen(header)) { JANUS_LOG(LOG_ERR, "Couldn't write .mjr header (%zu != %zu, %s)\n", - res, strlen(header), strerror(errno)); + res, strlen(header), g_strerror(errno)); cmdline_parser_free(&args_info); pcap_close(pcap); exit(1); @@ -289,12 +289,12 @@ int main(int argc, char *argv[]) size_t res = fwrite(&info_bytes, sizeof(uint16_t), 1, outfile); if(res != 1) { JANUS_LOG(LOG_WARN, "Couldn't write size of JSON header in .mjr file (%zu != %zu, %s), expect issues post-processing\n", - res, sizeof(uint16_t), strerror(errno)); + res, sizeof(uint16_t), g_strerror(errno)); } res = fwrite(info_text, sizeof(char), strlen(info_text), outfile); if(res != strlen(info_text)) { JANUS_LOG(LOG_WARN, "Couldn't write JSON header in .mjr file (%zu != %zu, %s), expect issues post-processing\n", - res, strlen(info_text), strerror(errno)); + res, strlen(info_text), g_strerror(errno)); } free(info_text); } @@ -302,20 +302,20 @@ int main(int argc, char *argv[]) size_t res = fwrite(frame_header, sizeof(char), strlen(frame_header), outfile); if(res != strlen(frame_header)) { JANUS_LOG(LOG_WARN, "Couldn't write frame header in .mjr file (%zu != %zu, %s), expect issues post-processing\n", - res, strlen(frame_header), strerror(errno)); + res, strlen(frame_header), g_strerror(errno)); } uint32_t timestamp = (uint32_t)(pkt_ts > start_ts ? ((pkt_ts - start_ts)/1000) : 0); timestamp = htonl(timestamp); res = fwrite(×tamp, sizeof(uint32_t), 1, outfile); if(res != 1) { JANUS_LOG(LOG_WARN, "Couldn't write frame timestamp in .mjr file (%zu != %zu, %s), expect issues post-processing\n", - res, sizeof(uint32_t), strerror(errno)); + res, sizeof(uint32_t), g_strerror(errno)); } uint16_t header_bytes = htons(pkt_size); res = fwrite(&header_bytes, sizeof(uint16_t), 1, outfile); if(res != 1) { JANUS_LOG(LOG_WARN, "Couldn't write size of frame in .mjr file (%zu != %zu, %s), expect issues post-processing\n", - res, sizeof(uint16_t), strerror(errno)); + res, sizeof(uint16_t), g_strerror(errno)); } /* Save packet on file */ written++; diff --git a/record.c b/record.c index d5117a8083e..334399b4c49 100644 --- a/record.c +++ b/record.c @@ -150,14 +150,14 @@ janus_recorder *janus_recorder_create_full(const char *dir, const char *codec, c if(ENOENT == errno) { /* Directory does not exist, try creating it */ if(janus_mkdir(rec_dir, 0755) < 0) { - JANUS_LOG(LOG_ERR, "mkdir (%s) error: %d (%s)\n", rec_dir, errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "mkdir (%s) error: %d (%s)\n", rec_dir, errno, g_strerror(errno)); janus_recorder_destroy(rc); g_free(copy_for_parent); g_free(copy_for_base); return NULL; } } else { - JANUS_LOG(LOG_ERR, "stat (%s) error: %d (%s)\n", rec_dir, errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "stat (%s) error: %d (%s)\n", rec_dir, errno, g_strerror(errno)); janus_recorder_destroy(rc); g_free(copy_for_parent); g_free(copy_for_base); @@ -238,7 +238,7 @@ janus_recorder *janus_recorder_create_full(const char *dir, const char *codec, c size_t res = fwrite(header, sizeof(char), strlen(header), rc->file); if(res != strlen(header)) { JANUS_LOG(LOG_ERR, "Couldn't write .mjr header (%zu != %zu, %s)\n", - res, strlen(header), strerror(errno)); + res, strlen(header), g_strerror(errno)); janus_recorder_destroy(rc); g_free(copy_for_parent); g_free(copy_for_base); @@ -339,12 +339,12 @@ int janus_recorder_save_frame(janus_recorder *recorder, char *buffer, uint lengt size_t res = fwrite(&info_bytes, sizeof(uint16_t), 1, recorder->file); if(res != 1) { JANUS_LOG(LOG_WARN, "Couldn't write size of JSON header in .mjr file (%zu != %zu, %s), expect issues post-processing\n", - res, sizeof(uint16_t), strerror(errno)); + res, sizeof(uint16_t), g_strerror(errno)); } res = fwrite(info_text, sizeof(char), strlen(info_text), recorder->file); if(res != strlen(info_text)) { JANUS_LOG(LOG_WARN, "Couldn't write JSON header in .mjr file (%zu != %zu, %s), expect issues post-processing\n", - res, strlen(info_text), strerror(errno)); + res, strlen(info_text), g_strerror(errno)); } free(info_text); /* Done */ @@ -355,20 +355,20 @@ int janus_recorder_save_frame(janus_recorder *recorder, char *buffer, uint lengt size_t res = fwrite(frame_header, sizeof(char), strlen(frame_header), recorder->file); if(res != strlen(frame_header)) { JANUS_LOG(LOG_WARN, "Couldn't write frame header in .mjr file (%zu != %zu, %s), expect issues post-processing\n", - res, strlen(frame_header), strerror(errno)); + res, strlen(frame_header), g_strerror(errno)); } uint32_t timestamp = (uint32_t)(now > recorder->started ? ((now - recorder->started)/1000) : 0); timestamp = htonl(timestamp); res = fwrite(×tamp, sizeof(uint32_t), 1, recorder->file); if(res != 1) { JANUS_LOG(LOG_WARN, "Couldn't write frame timestamp in .mjr file (%zu != %zu, %s), expect issues post-processing\n", - res, sizeof(uint32_t), strerror(errno)); + res, sizeof(uint32_t), g_strerror(errno)); } uint16_t header_bytes = htons(recorder->type == JANUS_RECORDER_DATA ? (length+sizeof(gint64)) : length); res = fwrite(&header_bytes, sizeof(uint16_t), 1, recorder->file); if(res != 1) { JANUS_LOG(LOG_WARN, "Couldn't write size of frame in .mjr file (%zu != %zu, %s), expect issues post-processing\n", - res, sizeof(uint16_t), strerror(errno)); + res, sizeof(uint16_t), g_strerror(errno)); } if(recorder->type == JANUS_RECORDER_DATA) { /* If it's data, then we need to prepend timing related info, as it's not there by itself */ @@ -376,7 +376,7 @@ int janus_recorder_save_frame(janus_recorder *recorder, char *buffer, uint lengt res = fwrite(&now, sizeof(gint64), 1, recorder->file); if(res != 1) { JANUS_LOG(LOG_WARN, "Couldn't write data timestamp in .mjr file (%zu != %zu, %s), expect issues post-processing\n", - res, sizeof(gint64), strerror(errno)); + res, sizeof(gint64), g_strerror(errno)); } } /* Save packet on file */ diff --git a/transports/janus_pfunix.c b/transports/janus_pfunix.c index d100cabb14e..bc8c53a7c78 100644 --- a/transports/janus_pfunix.c +++ b/transports/janus_pfunix.c @@ -188,7 +188,7 @@ static int janus_pfunix_create_socket(char *pfname, gboolean use_dgram) { int flags = use_dgram ? SOCK_DGRAM | SOCK_NONBLOCK : SOCK_SEQPACKET | SOCK_NONBLOCK; fd = socket(use_dgram ? AF_UNIX : PF_UNIX, flags, 0); if(fd < 0) { - JANUS_LOG(LOG_FATAL, "Unix Sockets %s creation failed: %d, %s\n", pfname, errno, strerror(errno)); + JANUS_LOG(LOG_FATAL, "Unix Sockets %s creation failed: %d, %s\n", pfname, errno, g_strerror(errno)); } else { /* Unlink before binding */ unlink(pfname); @@ -199,7 +199,7 @@ static int janus_pfunix_create_socket(char *pfname, gboolean use_dgram) { g_snprintf(address.sun_path, UNIX_PATH_MAX, "%s", pfname); JANUS_LOG(LOG_VERB, "Binding Unix Socket %s... (Janus API)\n", pfname); if(bind(fd, (struct sockaddr *)&address, sizeof(address)) != 0) { - JANUS_LOG(LOG_FATAL, "Bind for Unix Socket %s failed: %d, %s\n", pfname, errno, strerror(errno)); + JANUS_LOG(LOG_FATAL, "Bind for Unix Socket %s failed: %d, %s\n", pfname, errno, g_strerror(errno)); close(fd); fd = -1; return fd; @@ -207,7 +207,7 @@ static int janus_pfunix_create_socket(char *pfname, gboolean use_dgram) { if(!use_dgram) { JANUS_LOG(LOG_VERB, "Listening on Unix Socket %s...\n", pfname); if(listen(fd, 128) != 0) { - JANUS_LOG(LOG_FATAL, "Listening on Unix Socket %s failed: %d, %s\n", pfname, errno, strerror(errno)); + JANUS_LOG(LOG_FATAL, "Listening on Unix Socket %s failed: %d, %s\n", pfname, errno, g_strerror(errno)); close(fd); fd = -1; } @@ -275,7 +275,7 @@ int janus_pfunix_init(janus_transport_callbacks *callback, const char *config_pa /* First of all, initialize the socketpair for writeable notifications */ if(socketpair(PF_LOCAL, SOCK_STREAM, 0, write_fd) < 0) { - JANUS_LOG(LOG_FATAL, "Error creating socket pair for writeable events: %d, %s\n", errno, strerror(errno)); + JANUS_LOG(LOG_FATAL, "Error creating socket pair for writeable events: %d, %s\n", errno, g_strerror(errno)); return -1; } @@ -636,10 +636,10 @@ void *janus_pfunix_thread(void *data) { continue; if(res < 0) { if(errno == EINTR) { - JANUS_LOG(LOG_HUGE, "Got an EINTR (%s) polling the Unix Sockets descriptors, ignoring...\n", strerror(errno)); + JANUS_LOG(LOG_HUGE, "Got an EINTR (%s) polling the Unix Sockets descriptors, ignoring...\n", g_strerror(errno)); continue; } - JANUS_LOG(LOG_ERR, "poll() failed: %d (%s)\n", errno, strerror(errno)); + JANUS_LOG(LOG_ERR, "poll() failed: %d (%s)\n", errno, g_strerror(errno)); break; } int i = 0; @@ -655,7 +655,7 @@ void *janus_pfunix_thread(void *data) { close(write_fd[1]); write_fd[1] = -1; if(socketpair(PF_LOCAL, SOCK_STREAM, 0, write_fd) < 0) { - JANUS_LOG(LOG_FATAL, "Error creating socket pair for writeable events: %d, %s\n", errno, strerror(errno)); + JANUS_LOG(LOG_FATAL, "Error creating socket pair for writeable events: %d, %s\n", errno, g_strerror(errno)); continue; } } else if(poll_fds[i].fd == pfd) { diff --git a/utils.c b/utils.c index 45ea4b71992..c06f0c23aaf 100644 --- a/utils.c +++ b/utils.c @@ -482,7 +482,7 @@ int janus_pidfile_create(const char *file) { /* Write the PID */ pid = getpid(); if(fprintf(pidf, "%d\n", pid) < 0) { - JANUS_LOG(LOG_FATAL, "Error writing PID in file, error %d (%s)\n", errno, strerror(errno)); + JANUS_LOG(LOG_FATAL, "Error writing PID in file, error %d (%s)\n", errno, g_strerror(errno)); fclose(pidf); return -1; } @@ -528,7 +528,7 @@ gboolean janus_is_folder_protected(const char *path) { resolved[0] = '\0'; if(realpath(path, resolved) == NULL && errno != ENOENT) { JANUS_LOG(LOG_ERR, "Error resolving path '%s'... %d (%s)\n", - path, errno, strerror(errno)); + path, errno, g_strerror(errno)); return TRUE; } /* Traverse the list of protected folders to see if any match */ From 9b97164381efc0901dd8f3fc8a980f284514549f Mon Sep 17 00:00:00 2001 From: Alessandro Toppi Date: Mon, 22 Mar 2021 11:49:20 +0100 Subject: [PATCH 36/63] Add some checks to publisher destroyed flag. --- plugins/janus_videoroom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index 56852477aa2..fb766f752cd 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -3656,7 +3656,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi g_hash_table_iter_init(&iter, videoroom->participants); while (g_hash_table_iter_next(&iter, NULL, &value)) { janus_videoroom_publisher *p = value; - if(p && p->session && p->room) { + if(p && !g_atomic_int_get(&p->destroyed) && p->session && p->room) { g_clear_pointer(&p->room, janus_videoroom_room_dereference); /* Notify the user we're going to destroy the room... */ int ret = gateway->push_event(p->session->handle, &janus_videoroom_plugin, NULL, destroyed, NULL); @@ -4512,7 +4512,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi /* This publisher is leaving, tell everybody */ janus_videoroom_leave_or_unpublish(participant, TRUE, TRUE); /* Tell the core to tear down the PeerConnection, hangup_media will do the rest */ - if(participant && participant->session) + if(participant && !g_atomic_int_get(&participant->destroyed) && participant->session) gateway->close_pc(participant->session->handle); JANUS_LOG(LOG_INFO, "Kicked user %s from room %s\n", user_id_str, room_id_str); /* Prepare response */ From ef8f98801a8972fc5862ff3800f564fa9ac452d1 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 22 Mar 2021 12:01:32 +0100 Subject: [PATCH 37/63] Fixed typos in Changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d7a161de7e..55d77fe5b7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,10 +9,10 @@ All notable changes to this project will be documented in this file. - Close libnice agent resources asynchronously when hanging up PeerConnections (thanks @fbellet!) [[PR-2492](#2492)] - Fixed broken parsing of SDP when trying to match specific codec profiles [[PR-2549](#2549)] - Added muting/moderation API to the VideoRoom plugin [[PR-2513](#2513)] -- Fixed a few race conditions in VideoRoom plugin that could lead to crashes [[PR-2539][#2539)] +- Fixed a few race conditions in VideoRoom plugin that could lead to crashes [[PR-2539](#2539)] - Send 480 instead of BYE when hanging up calls in early dialog in the SIP plugin (thanks @zayim!) [[PR-2521](#2521)] - Added configurable media direction when putting calls on-hold in the SIP plugin [[PR-2525](#2525)] -- Fixed rare race condition in AudioBridge when using "changeroom" (thanks @JeckLabs!) [[PR-2535][#2535)] +- Fixed rare race condition in AudioBridge when using "changeroom" (thanks @JeckLabs!) [[PR-2535](#2535)] - Fixed broken API secret management in HTTP long polls (thanks @remvst!) [[PR-2524](#2524)] - Report failure if binding to a socket fails in WebSockets transport plugin (thanks @Symbiatch!) [[PR-2534](#2534)] - Updated RabbitMQ logic in both transport and event handler (thanks @chriswiggins!) [[PR-2430](#2430)] From 01529b6faa395ebeeb106928db30c7138c5225eb Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 22 Mar 2021 12:06:17 +0100 Subject: [PATCH 38/63] Added check on participant destroyed flag before sending events --- plugins/janus_videoroom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index fb766f752cd..cde42748993 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -2653,7 +2653,7 @@ static void janus_videoroom_notify_participants(janus_videoroom_publisher *parti g_hash_table_iter_init(&iter, participant->room->participants); while (participant->room && !g_atomic_int_get(&participant->room->destroyed) && g_hash_table_iter_next(&iter, NULL, &value)) { janus_videoroom_publisher *p = value; - if(p && p->session && (p != participant || notify_source_participant)) { + if(p && !g_atomic_int_get(&p->destroyed) && p->session && (p != participant || notify_source_participant)) { JANUS_LOG(LOG_VERB, "Notifying participant %s (%s)\n", p->user_id_str, p->display ? p->display : "??"); int ret = gateway->push_event(p->session->handle, &janus_videoroom_plugin, NULL, msg, NULL); JANUS_LOG(LOG_VERB, " >> %d (%s)\n", ret, janus_get_api_error(ret)); From 9fc7c3b1bf4b9f191d75eacc97488308b99eed31 Mon Sep 17 00:00:00 2001 From: Alessandro Toppi Date: Mon, 22 Mar 2021 12:15:19 +0100 Subject: [PATCH 39/63] Fix warning about comparison of integers of different signedness in rtcp. --- rtcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtcp.c b/rtcp.c index b0455a810ad..c00423f28d6 100644 --- a/rtcp.c +++ b/rtcp.c @@ -346,7 +346,7 @@ static void janus_rtcp_rr_update_stats(rtcp_context *ctx, janus_report_block rb) ctx->rr_last_ts = ts; uint32_t total_lost = ntohl(rb.flcnpl) & 0x00FFFFFF; if (ctx->rr_last_ehsnr != 0) { - uint32_t sent = g_atomic_int_get(&ctx->sent_packets_since_last_rr); + int32_t sent = g_atomic_int_get(&ctx->sent_packets_since_last_rr); uint32_t expect = ntohl(rb.ehsnr) - ctx->rr_last_ehsnr; int32_t nacks = g_atomic_int_get(&ctx->nack_count) - ctx->rr_last_nack_count; /* In case the number of NACKs is higher than the number of sent packets, From 75b658ebd6b34953648ad02a85183128c1c64006 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 22 Mar 2021 12:33:51 +0100 Subject: [PATCH 40/63] Added more videos to the list of presentations in the FAQ --- mainpage.dox | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mainpage.dox b/mainpage.dox index b28bed6493e..f6c4c608bfb 100644 --- a/mainpage.dox +++ b/mainpage.dox @@ -3914,7 +3914,12 @@ ldd janus | grep asan * - Presentation on using Janus for Virtual Events at CommCon 2020; * - Workshop on Janus (lesson/tutorial) at ClueCon 2020; * - Presentation on E2EE (end-to-end encryption) and Insertable Streams at ClueCon 2020; - * - Presentation on SFUs and MCUs at IIT RTC 2020. \n\n + * - Presentation on SFUs and MCUs at IIT RTC 2020; + * - Presentation on using Janus for IETF Virtual Participation at the MOPS WG session (IETF109); + * - Presentation on WebRTC (and Janus) as a way to help musicians at FOSDEM 2021; + * - Workshop on Janus RTP forwarders (lesson/tutorial) at ClueCon TGI2021; + * - Presentation on Janus and NDI at ClueCon TGI2021; + * - Presentation on Janus and multicast at the MBONED WG session (IETF 110). \n\n * Apart from these presentations, make sure you also check the slides * and presentations from JanusCon, * the Janus conference we hosted here in Napoli. From 414edcae7955b924f8a434909fafe243c2ad8d6c Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Mon, 22 Mar 2021 12:54:01 +0100 Subject: [PATCH 41/63] Document 'timeout' and 'detached' events (fixes #2576) --- mainpage.dox | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/mainpage.dox b/mainpage.dox index f6c4c608bfb..8300d4d3822 100644 --- a/mainpage.dox +++ b/mainpage.dox @@ -1385,6 +1385,16 @@ GET http://host:port/janus/?maxev=5 * destroy request, but a cleaner approach on the client side would help * nonetheless avoid potential issues. * + * Notice that a session may also be destroyed automatically in case of + * inactivity. If Janus doesn't receive any activity (requests, long polls) + * for a session for a time longer than the \c session_timeout value + * configured in \c janus.jcfg then the session will timeout, and a + * \c timeout event will be fired. If a \c reclaim_session_timeout value + * is configured, you can still reclaim the session from the same or + * a different transport using the \c claim request, within a limited + * amount of time. An unreclaimed session that has timed out will be + * permanently destroyed, and will destroy all its handles as well. + * * \section handles The plugin handle endpoint * Once you've created a plugin handle, a new endpoint you can use is created * in the server. Specifically, the new endpoint is constructed by @@ -1565,7 +1575,9 @@ GET http://host:port/janus/?maxev=5 * with the plugin, make sure it is torn down as part of this process. * The plugin implementation and the Janus core should do this * automatically, but implementing the right behaviour in clients would - * help avoid potential issues nonetheless. + * help avoid potential issues nonetheless. Notice that you may receive + * \c detached event after a handle has been detached, whether this was + * done in response to a request or automatically, in response to an event. * * If you're interested in keeping the handle alive but want to hang up * the associated PeerConnection, if available, just send a "hangup" \c janus @@ -1791,9 +1803,10 @@ var websocket = new WebSocket('ws://1.2.3.4:8188', 'janus-protocol'); * originated them. * * An \b important aspect to point out is related to keep-alive messages - * for WebSockets Janus channels. A Janus session is kept alive as long - * as there's no inactivity for 60 seconds: if no messages have been - * received in that time frame, the session is torn down by the server. + * for WebSockets Janus channels. As explained above, a Janus session is + * kept alive as long as there's no inactivity for \c session_timeout seconds: + * if no messages have been received in that time frame, the session is + * marked as timed-out and, unless reclaimed, will be torn down by the server. * A normal activity on a session is usually enough to prevent that; * for a more prolonged inactivity with respect to messaging, on plain * HTTP the session is usually kept alive through the regular long poll From e935cdc395a1dc5a899510dcc565c3a92823f871 Mon Sep 17 00:00:00 2001 From: Aleksey Gureiev Date: Thu, 25 Mar 2021 18:50:49 +0300 Subject: [PATCH 42/63] Added support for admin-protected custom session timeouts (#2577) --- janus.c | 78 ++++++++++++++++++++++++++++++++++++++++------------ janus.h | 4 ++- mainpage.dox | 3 +- 3 files changed, 66 insertions(+), 19 deletions(-) diff --git a/janus.c b/janus.c index 13ae5615855..ea2b1f56e8b 100644 --- a/janus.c +++ b/janus.c @@ -124,6 +124,9 @@ static struct janus_json_parameter debug_parameters[] = { static struct janus_json_parameter timeout_parameters[] = { {"timeout", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE} }; +static struct janus_json_parameter session_timeout_parameters[] = { + {"timeout", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED} +}; static struct janus_json_parameter level_parameters[] = { {"level", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE} }; @@ -275,7 +278,7 @@ static json_t *janus_create_message(const char *status, uint64_t session_id, con * incurring in unexpected timeouts (when HTTP is used in janus.js, the * long poll is used as a keepalive mechanism). */ #define DEFAULT_SESSION_TIMEOUT 60 -static uint session_timeout = DEFAULT_SESSION_TIMEOUT; +static uint global_session_timeout = DEFAULT_SESSION_TIMEOUT; #define DEFAULT_RECLAIM_SESSION_TIMEOUT 0 static uint reclaim_session_timeout = DEFAULT_RECLAIM_SESSION_TIMEOUT; @@ -326,7 +329,7 @@ static json_t *janus_info(const char *transaction) { json_object_set_new(info, "data_channels", json_false()); #endif json_object_set_new(info, "accepting-new-sessions", accept_new_sessions ? json_true() : json_false()); - json_object_set_new(info, "session-timeout", json_integer(session_timeout)); + json_object_set_new(info, "session-timeout", json_integer(global_session_timeout)); json_object_set_new(info, "reclaim-session-timeout", json_integer(reclaim_session_timeout)); json_object_set_new(info, "candidates-timeout", json_integer(candidates_timeout)); json_object_set_new(info, "server-name", json_string(server_name ? server_name : JANUS_SERVER_NAME)); @@ -655,8 +658,6 @@ static void janus_request_unref(janus_request *request) { } static gboolean janus_check_sessions(gpointer user_data) { - if(session_timeout < 1 && reclaim_session_timeout < 1) /* Session timeouts are disabled */ - return G_SOURCE_CONTINUE; janus_mutex_lock(&sessions_mutex); if(sessions && g_hash_table_size(sessions) > 0) { GHashTableIter iter; @@ -668,10 +669,15 @@ static gboolean janus_check_sessions(gpointer user_data) { continue; } gint64 now = janus_get_monotonic_time(); - if ((session_timeout > 0 && (now - session->last_activity >= (gint64)session_timeout * G_USEC_PER_SEC) && - !g_atomic_int_compare_and_exchange(&session->timeout, 0, 1)) || + + /* Use either session-specific timeout or global. */ + gint64 timeout = (gint64)session->timeout; + if (timeout == -1) timeout = (gint64)global_session_timeout; + + if ((timeout > 0 && (now - session->last_activity >= timeout * G_USEC_PER_SEC) && + !g_atomic_int_compare_and_exchange(&session->timedout, 0, 1)) || ((g_atomic_int_get(&session->transport_gone) && now - session->last_activity >= (gint64)reclaim_session_timeout * G_USEC_PER_SEC) && - !g_atomic_int_compare_and_exchange(&session->timeout, 0, 1))) { + !g_atomic_int_compare_and_exchange(&session->timedout, 0, 1))) { JANUS_LOG(LOG_INFO, "Timeout expired for session %"SCNu64"...\n", session->session_id); /* Mark the session as over, we'll deal with it later */ janus_session_handles_clear(session); @@ -739,8 +745,9 @@ janus_session *janus_session_create(guint64 session_id) { session->session_id = session_id; janus_refcount_init(&session->ref, janus_session_free); session->source = NULL; + session->timeout = -1; /* Negative means rely on global timeout */ g_atomic_int_set(&session->destroyed, 0); - g_atomic_int_set(&session->timeout, 0); + g_atomic_int_set(&session->timedout, 0); g_atomic_int_set(&session->transport_gone, 0); session->last_activity = janus_get_monotonic_time(); session->ice_handles = NULL; @@ -1063,6 +1070,7 @@ int janus_process_incoming_request(janus_request *request) { goto jsondone; } } + /* Handle it */ session = janus_session_create(session_id); if(session == NULL) { @@ -1981,7 +1989,7 @@ int janus_process_incoming_admin_request(janus_request *request) { json_t *reply = janus_create_message("success", 0, transaction_text); json_t *status = json_object(); json_object_set_new(status, "token_auth", janus_auth_is_enabled() ? json_true() : json_false()); - json_object_set_new(status, "session_timeout", json_integer(session_timeout)); + json_object_set_new(status, "session_timeout", json_integer(global_session_timeout)); json_object_set_new(status, "reclaim_session_timeout", json_integer(reclaim_session_timeout)); json_object_set_new(status, "candidates_timeout", json_integer(candidates_timeout)); json_object_set_new(status, "log_level", json_integer(janus_log_level)); @@ -1999,7 +2007,6 @@ int janus_process_incoming_admin_request(janus_request *request) { ret = janus_process_success(request, reply); goto jsondone; } else if(!strcasecmp(message_text, "set_session_timeout")) { - /* Change the session timeout value */ JANUS_VALIDATE_JSON_OBJECT(root, timeout_parameters, error_code, error_cause, FALSE, JANUS_ERROR_MISSING_MANDATORY_ELEMENT, JANUS_ERROR_INVALID_ELEMENT_TYPE); @@ -2013,12 +2020,16 @@ int janus_process_incoming_admin_request(janus_request *request) { ret = janus_process_error(request, session_id, transaction_text, JANUS_ERROR_INVALID_ELEMENT_TYPE, "Invalid element type (timeout should be a positive integer)"); goto jsondone; } - session_timeout = timeout_num; + + /* Set global session timeout */ + global_session_timeout = timeout_num; + /* Prepare JSON reply */ json_t *reply = json_object(); json_object_set_new(reply, "janus", json_string("success")); json_object_set_new(reply, "transaction", json_string(transaction_text)); - json_object_set_new(reply, "timeout", json_integer(session_timeout)); + json_object_set_new(reply, "timeout", json_integer(timeout_num)); + /* Send the success reply */ ret = janus_process_success(request, reply); goto jsondone; @@ -2668,12 +2679,45 @@ int janus_process_incoming_admin_request(janus_request *request) { janus_events_notify_handlers(JANUS_EVENT_TYPE_SESSION, JANUS_EVENT_SUBTYPE_NONE, session_id, "destroyed", NULL); goto jsondone; - } - /* If this is not a request to destroy a session, it must be a request to list the handles */ - if(strcasecmp(message_text, "list_handles")) { + } else if (!strcasecmp(message_text, "set_session_timeout")) { + /* Specific session timeout setting. */ + JANUS_VALIDATE_JSON_OBJECT(root, session_timeout_parameters, + error_code, error_cause, FALSE, + JANUS_ERROR_MISSING_MANDATORY_ELEMENT, JANUS_ERROR_INVALID_ELEMENT_TYPE); + if(error_code != 0) { + ret = janus_process_error_string(request, session_id, transaction_text, error_code, error_cause); + goto jsondone; + } + + /* Positive timeout is seconds, 0 is unlimited, -1 is global session timeout */ + json_t *timeout = json_object_get(root, "timeout"); + int timeout_num = json_integer_value(timeout); + if(timeout_num < -1) { + ret = janus_process_error(request, session_id, transaction_text, JANUS_ERROR_INVALID_ELEMENT_TYPE, "Invalid element type (timeout should be a non-negative integer or -1)"); + goto jsondone; + } + + /* Set specific session timeout */ + janus_mutex_lock(&session->mutex); + session->timeout = timeout_num; + janus_mutex_unlock(&session->mutex); + + /* Prepare JSON reply */ + json_t *reply = json_object(); + json_object_set_new(reply, "janus", json_string("success")); + json_object_set_new(reply, "transaction", json_string(transaction_text)); + json_object_set_new(reply, "timeout", json_integer(timeout_num)); + json_object_set_new(reply, "session_id", json_integer(session_id)); + + /* Send the success reply */ + ret = janus_process_success(request, reply); + goto jsondone; + } else if(strcasecmp(message_text, "list_handles")) { + /* If this is not a request to destroy a session, it must be a request to list the handles */ ret = janus_process_error(request, session_id, transaction_text, JANUS_ERROR_INVALID_REQUEST_PATH, "Unhandled request '%s' at this path", message_text); goto jsondone; } + /* List handles */ json_t *list = janus_session_handles_list_json(session); /* Prepare JSON reply */ @@ -3229,7 +3273,7 @@ void janus_transport_gone(janus_transport *plugin, janus_transport_session *tran g_hash_table_iter_init(&iter, sessions); while(g_hash_table_iter_next(&iter, NULL, &value)) { janus_session *session = (janus_session *) value; - if(!session || g_atomic_int_get(&session->destroyed) || g_atomic_int_get(&session->timeout) || session->last_activity == 0) + if(!session || g_atomic_int_get(&session->destroyed) || g_atomic_int_get(&session->timedout) || session->last_activity == 0) continue; if(session->source && session->source->instance == transport) { JANUS_LOG(LOG_VERB, " -- Session %"SCNu64" will be over if not reclaimed\n", session->session_id); @@ -4577,7 +4621,7 @@ gint main(int argc, char *argv[]) if(st == 0) { JANUS_LOG(LOG_WARN, "Session timeouts have been disabled (note, may result in orphaned sessions)\n"); } - session_timeout = st; + global_session_timeout = st; } } diff --git a/janus.h b/janus.h index 476acd23327..e86a72f2b32 100644 --- a/janus.h +++ b/janus.h @@ -53,7 +53,9 @@ typedef struct janus_session { /*! \brief Pointer to the request instance (and the transport that originated the session) */ janus_request *source; /*! \brief Flag to notify there's been a session timeout */ - volatile gint timeout; + volatile gint timedout; + /*! \brief Timeout value in seconds to use with this session, 0 is unlimited, -1 is global session timeout setting */ + gint timeout; /*! \brief Flag to notify that transport is gone */ volatile gint transport_gone; /*! \brief Mutex to lock/unlock this session */ diff --git a/mainpage.dox b/mainpage.dox index 8300d4d3822..eb909a7a911 100644 --- a/mainpage.dox +++ b/mainpage.dox @@ -2276,7 +2276,7 @@ const token = getJanusToken('janus', ['janus.plugin.videoroom']), * \subsection adminreqc Configuration-related requests * - \c get_status: returns the current value for the settings that can be * modified at runtime via the Admin API (see below); - * - \c set_session_timeout: change the session timeout value in Janus; + * - \c set_session_timeout: change global session timeout value in Janus; * - \c set_log_level: change the log level in Janus; * - \c set_log_timestamps: selectively enable/disable adding a timestamp * to all log lines Janus writes on the console and/or to file; @@ -2306,6 +2306,7 @@ const token = getJanusToken('janus', ['janus.plugin.videoroom']), * you want to stop accepting new sessions because you're draining this instance; * - \c list_sessions: list all the sessions currently active in Janus * (returns an array of session identifiers); + * - \c set_session_timeout: change session timeout value in Janus; * - \c destroy_session: destroy a specific session; this behaves exactly * as the \c destroy request does in the Janus API. * From 7c9d522ede2c38fbd4e9b7f21e4d443698d8819e Mon Sep 17 00:00:00 2001 From: Jesper Schmitz Mouridsen Date: Thu, 25 Mar 2021 16:59:24 +0100 Subject: [PATCH 43/63] FreeBSD support (#2508) --- README.md | 11 +++++++ configure.ac | 31 ++++++++++++++++---- plugins/janus_audiobridge.c | 4 +++ postprocessing/janus-pp-rec.c | 2 +- postprocessing/mjr2pcap.c | 2 +- postprocessing/pp-av1.c | 2 +- postprocessing/pp-binary.c | 2 +- postprocessing/pp-g711.c | 2 +- postprocessing/pp-g722.c | 2 +- postprocessing/pp-h264.c | 2 +- postprocessing/pp-h265.c | 2 +- postprocessing/pp-opus.c | 2 +- postprocessing/pp-rtp.h | 2 +- postprocessing/pp-srt.c | 2 +- postprocessing/pp-webm.c | 2 +- rtcp.h | 2 ++ rtp.h | 2 +- text2pcap.c | 5 ++++ transports/janus_websockets.c | 55 +++++++++++++++++++++++++++++++++-- 19 files changed, 114 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index eb508ffbff1..3c86cac1a6a 100644 --- a/README.md +++ b/README.md @@ -207,6 +207,17 @@ If Doxygen and graphviz are available, the process can also build the documentat You can also selectively enable/disable other features (e.g., specific plugins you don't care about, or whether or not you want to build the recordings post-processor). Use the --help option when configuring for more info. +### Building on FreeBSD +* *Note*: rtp_forward of streams only works streaming to IPv6, +because of #2051 and thus the feature is not supported on FreeBSD at the moment. + +When building on FreeBSD you can install the depencencies from ports or packages, here only pkg method is used. You also need to use `gmake` instead of `make`, +since it is a GNU makefile. `./configure` can be run without arguments since the default prefix is `/usr/local` which is your default `LOCALBASE`. +Note that the `configure.ac` is coded to use openssl in base. If you wish to use openssl from ports or any other ssl you must change `configure.ac` accordingly. + + pkg install libsrtp2 libusrsctp jansson libnice libmicrohttpd libwebsockets curl opus sofia-sip libogg jansson libnice libconfig \ + libtool gmake autoconf autoconf-wrapper glib gengetopt + ### Building on MacOS While most of the above instructions will work when compiling Janus on MacOS as well, there are a few aspects to highlight when doing that. diff --git a/configure.ac b/configure.ac index f305d527598..5bc18a71813 100644 --- a/configure.ac +++ b/configure.ac @@ -61,6 +61,11 @@ clang*) -Wno-cast-align \ -Wno-initializer-overrides" ;; +cc*) + CFLAGS="$CFLAGS \ + -Wno-cast-align \ + -Wno-initializer-overrides" +;; *) # Specific gcc flags CFLAGS="$CFLAGS \ @@ -83,6 +88,12 @@ darwin*) LDFLAGS="$LDFLAGS -L/usr/local/lib -L/usr/local/opt/openssl/lib -L/opt/local/lib -L/usr/local/libsrtp/lib" AM_CONDITIONAL([DARWIN_OS], true) ;; +freebsd*) + CFLAGS="$CFLAGS -I/usr/include/openssl" + LDFLAGS="$LDFLAGS -Xlinker --export-dynamic" + LDFLAGS="$LDFLAGS -L/usr/lib/openssl -lcrypto -lssl -L/usr/local/lib" + AM_CONDITIONAL([DARWIN_OS], false) +;; *) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" AM_CONDITIONAL([DARWIN_OS], false) @@ -337,17 +348,27 @@ AC_ARG_ENABLE([systemd-sockets], [], [enable_systemd_sockets=no]) -PKG_CHECK_MODULES([JANUS], - [ - glib-2.0 >= $glib_version +case "$host_os" in +freebsd*) + PKGCHECKMODULES="glib-2.0 >= $glib_version + gio-2.0 >= $glib_version + libconfig + nice + jansson >= $jansson_version + zlib" +;; +*) + PKGCHECKMODULES="glib-2.0 >= $glib_version gio-2.0 >= $glib_version libconfig nice jansson >= $jansson_version libssl >= $ssl_version libcrypto - zlib - ]) + zlib" +esac +PKG_CHECK_MODULES([JANUS],"$PKGCHECKMODULES") + JANUS_MANUAL_LIBS="${JANUS_MANUAL_LIBS} -lm" AC_SUBST(JANUS_MANUAL_LIBS) diff --git a/plugins/janus_audiobridge.c b/plugins/janus_audiobridge.c index f92c5d4a3f1..763c8d96ba3 100644 --- a/plugins/janus_audiobridge.c +++ b/plugins/janus_audiobridge.c @@ -857,6 +857,10 @@ room-: { */ #include "plugin.h" +#ifdef __FreeBSD__ +#include +#include +#endif #include #include diff --git a/postprocessing/janus-pp-rec.c b/postprocessing/janus-pp-rec.c index b2c36887464..aa11ba1e485 100644 --- a/postprocessing/janus-pp-rec.c +++ b/postprocessing/janus-pp-rec.c @@ -88,7 +88,7 @@ Usage: janus-pp-rec [OPTIONS] source.mjr [destination.[opus|wav|webm|mp4|srt]] */ #include -#ifdef __MACH__ +#if defined(__MACH__) || defined(__FreeBSD__) #include #else #include diff --git a/postprocessing/mjr2pcap.c b/postprocessing/mjr2pcap.c index 3b5997fea96..7d9e7cce89b 100644 --- a/postprocessing/mjr2pcap.c +++ b/postprocessing/mjr2pcap.c @@ -25,7 +25,7 @@ */ #include -#ifdef __MACH__ +#if defined(__MACH__) || defined(__FreeBSD__) #include #else #include diff --git a/postprocessing/pp-av1.c b/postprocessing/pp-av1.c index 4b7493eb5bc..b2139c7b60e 100644 --- a/postprocessing/pp-av1.c +++ b/postprocessing/pp-av1.c @@ -10,7 +10,7 @@ */ #include -#ifdef __MACH__ +#if defined(__MACH__) || defined(__FreeBSD__) #include #else #include diff --git a/postprocessing/pp-binary.c b/postprocessing/pp-binary.c index 4bc4c62e5b6..ae52eece63a 100644 --- a/postprocessing/pp-binary.c +++ b/postprocessing/pp-binary.c @@ -12,7 +12,7 @@ */ #include -#ifdef __MACH__ +#if defined(__MACH__) || defined(__FreeBSD__) #include #else #include diff --git a/postprocessing/pp-g711.c b/postprocessing/pp-g711.c index d6d78aee999..073cfe67dc3 100644 --- a/postprocessing/pp-g711.c +++ b/postprocessing/pp-g711.c @@ -10,7 +10,7 @@ */ #include -#ifdef __MACH__ +#if defined(__MACH__) || defined(__FreeBSD__) #include #else #include diff --git a/postprocessing/pp-g722.c b/postprocessing/pp-g722.c index b03670d6975..d85506e8fc7 100644 --- a/postprocessing/pp-g722.c +++ b/postprocessing/pp-g722.c @@ -10,7 +10,7 @@ */ #include -#ifdef __MACH__ +#if defined (__MACH__) || defined(__FreeBSD__) #include #else #include diff --git a/postprocessing/pp-h264.c b/postprocessing/pp-h264.c index dfa639193ef..bd02cb32aa1 100644 --- a/postprocessing/pp-h264.c +++ b/postprocessing/pp-h264.c @@ -10,7 +10,7 @@ */ #include -#ifdef __MACH__ +#if defined(__MACH__) || defined(__FreeBSD__) #include #else #include diff --git a/postprocessing/pp-h265.c b/postprocessing/pp-h265.c index 4e704b81104..d12aee8bfa8 100644 --- a/postprocessing/pp-h265.c +++ b/postprocessing/pp-h265.c @@ -10,7 +10,7 @@ */ #include -#ifdef __MACH__ +#if defined(__MACH__) || defined(__FreeBSD__) #include #else #include diff --git a/postprocessing/pp-opus.c b/postprocessing/pp-opus.c index 5dede3ef420..4eef9952e11 100644 --- a/postprocessing/pp-opus.c +++ b/postprocessing/pp-opus.c @@ -10,7 +10,7 @@ */ #include -#ifdef __MACH__ +#if defined(__MACH__) || defined(__FreeBSD__) #include #else #include diff --git a/postprocessing/pp-rtp.h b/postprocessing/pp-rtp.h index 121fa739b94..6880592b02f 100644 --- a/postprocessing/pp-rtp.h +++ b/postprocessing/pp-rtp.h @@ -13,7 +13,7 @@ #ifndef JANUS_PP_RTP #define JANUS_PP_RTP -#ifdef __MACH__ +#if defined(__MACH__) || defined(__FreeBSD__) #include #define __BYTE_ORDER BYTE_ORDER #define __BIG_ENDIAN BIG_ENDIAN diff --git a/postprocessing/pp-srt.c b/postprocessing/pp-srt.c index cb8d2859e24..5eeed71b8c9 100644 --- a/postprocessing/pp-srt.c +++ b/postprocessing/pp-srt.c @@ -10,7 +10,7 @@ */ #include -#ifdef __MACH__ +#if defined(__MACH__) || defined(__FreeBSD__) #include #else #include diff --git a/postprocessing/pp-webm.c b/postprocessing/pp-webm.c index cbf88f979ce..17a394758fd 100644 --- a/postprocessing/pp-webm.c +++ b/postprocessing/pp-webm.c @@ -10,7 +10,7 @@ */ #include -#ifdef __MACH__ +#if defined(__MACH__) || defined(__FreeBSD__) #include #else #include diff --git a/rtcp.h b/rtcp.h index 95862f51371..f9a3aba7ca6 100644 --- a/rtcp.h +++ b/rtcp.h @@ -19,6 +19,8 @@ #include #ifdef __MACH__ #include +#elif defined(__FreeBSD__) +#include #else #include #endif diff --git a/rtp.h b/rtp.h index 92284e779d2..97fa1d6c0e5 100644 --- a/rtp.h +++ b/rtp.h @@ -14,7 +14,7 @@ #define JANUS_RTP_H #include -#ifdef __MACH__ +#if defined (__MACH__) || defined(__FreeBSD__) #include #define __BYTE_ORDER BYTE_ORDER #define __BIG_ENDIAN BIG_ENDIAN diff --git a/text2pcap.c b/text2pcap.c index 06680c1d0af..4ab04adf91d 100644 --- a/text2pcap.c +++ b/text2pcap.c @@ -41,6 +41,11 @@ #define __BYTE_ORDER BYTE_ORDER #define __BIG_ENDIAN BIG_ENDIAN #define __LITTLE_ENDIAN LITTLE_ENDIAN +#elif defined(__FreeBSD__) +#include +#define __BYTE_ORDER BYTE_ORDER +#define __BIG_ENDIAN BIG_ENDIAN +#define __LITTLE_ENDIAN LITTLE_ENDIAN #else #include #endif diff --git a/transports/janus_websockets.c b/transports/janus_websockets.c index 4d2b8e34862..4784c328450 100644 --- a/transports/janus_websockets.c +++ b/transports/janus_websockets.c @@ -386,6 +386,9 @@ int janus_websockets_init(janus_transport_callbacks *callback, const char *confi JANUS_LOG(LOG_WARN, "libwebsockets has been built without IPv6 support, will bind to IPv4 only\n"); #endif +#ifdef __FreeBSD__ + int ipv4_only = 0; +#endif /* This is the callback we'll need to invoke to contact the Janus core */ gateway = callback; @@ -618,6 +621,11 @@ int janus_websockets_init(janus_transport_callbacks *callback, const char *confi item = janus_config_get(config, config_general, janus_config_type_item, "ws_ip"); if(item && item->value) { ip = (char *)item->value; +#ifdef __FreeBSD__ + struct in_addr addr; + if(inet_net_pton(AF_INET, ip, &addr, sizeof(addr)) > 0) + ipv4_only = 1; +#endif char *iface = janus_websockets_get_interface_name(ip); if(iface == NULL) { JANUS_LOG(LOG_WARN, "No interface associated with %s? Falling back to no interface...\n", ip); @@ -636,8 +644,16 @@ int janus_websockets_init(janus_transport_callbacks *callback, const char *confi info.ssl_private_key_password = NULL; info.gid = -1; info.uid = -1; + info.options = 0; +#ifdef __FreeBSD__ + if (ipv4_only) { + info.options |= LWS_SERVER_OPTION_DISABLE_IPV6; + ipv4_only = 0; + } +#endif #if (LWS_LIBRARY_VERSION_MAJOR == 3 && LWS_LIBRARY_VERSION_MINOR >= 2) || (LWS_LIBRARY_VERSION_MAJOR > 3) - info.options = LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND; + info.options |= LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND; + #endif /* Create the WebSocket context */ wss = lws_create_vhost(wsc, &info); @@ -666,6 +682,11 @@ int janus_websockets_init(janus_transport_callbacks *callback, const char *confi item = janus_config_get(config, config_general, janus_config_type_item, "wss_ip"); if(item && item->value) { ip = (char *)item->value; +#ifdef __FreeBSD__ + struct in_addr addr; + if(inet_net_pton(AF_INET, ip, &addr, sizeof(addr)) > 0) + ipv4_only = 1; +#endif char *iface = janus_websockets_get_interface_name(ip); if(iface == NULL) { JANUS_LOG(LOG_WARN, "No interface associated with %s? Falling back to no interface...\n", ip); @@ -707,6 +728,12 @@ int janus_websockets_init(janus_transport_callbacks *callback, const char *confi info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT | LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND; #elif LWS_LIBRARY_VERSION_MAJOR >= 2 info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; +#endif +#ifdef __FreeBSD__ + if(ipv4_only) { + info.options |= LWS_SERVER_OPTION_DISABLE_IPV6; + ipv4_only = 0; + } #endif /* Create the secure WebSocket context */ swss = lws_create_vhost(wsc, &info); @@ -737,6 +764,11 @@ int janus_websockets_init(janus_transport_callbacks *callback, const char *confi item = janus_config_get(config, config_admin, janus_config_type_item, "admin_ws_ip"); if(item && item->value) { ip = (char *)item->value; +#ifdef __FreeBSD__ + struct in_addr addr; + if(inet_net_pton(AF_INET, ip, &addr, sizeof(addr)) > 0) + ipv4_only = 1; +#endif char *iface = janus_websockets_get_interface_name(ip); if(iface == NULL) { JANUS_LOG(LOG_WARN, "No interface associated with %s? Falling back to no interface...\n", ip); @@ -755,8 +787,16 @@ int janus_websockets_init(janus_transport_callbacks *callback, const char *confi info.ssl_private_key_password = NULL; info.gid = -1; info.uid = -1; + info.options = 0; +#ifdef __FreeBSD__ + if (ipv4_only) { + info.options |= LWS_SERVER_OPTION_DISABLE_IPV6; + ipv4_only = 0; + } +#endif #if (LWS_LIBRARY_VERSION_MAJOR == 3 && LWS_LIBRARY_VERSION_MINOR >= 2) || (LWS_LIBRARY_VERSION_MAJOR > 3) - info.options = LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND; + info.options |= LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND; + #endif /* Create the WebSocket context */ admin_wss = lws_create_vhost(wsc, &info); @@ -785,6 +825,11 @@ int janus_websockets_init(janus_transport_callbacks *callback, const char *confi item = janus_config_get(config, config_admin, janus_config_type_item, "admin_wss_ip"); if(item && item->value) { ip = (char *)item->value; +#ifdef __FreeBSD__ + struct in_addr addr; + if(inet_net_pton(AF_INET, ip, &addr, sizeof(addr)) > 0) + ipv4_only = 1; +#endif char *iface = janus_websockets_get_interface_name(ip); if(iface == NULL) { JANUS_LOG(LOG_WARN, "No interface associated with %s? Falling back to no interface...\n", ip); @@ -826,6 +871,12 @@ int janus_websockets_init(janus_transport_callbacks *callback, const char *confi info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT | LWS_SERVER_OPTION_FAIL_UPON_UNABLE_TO_BIND; #elif LWS_LIBRARY_VERSION_MAJOR >= 2 info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; +#endif +#ifdef __FreeBSD__ + if (ipv4_only) { + info.options |= LWS_SERVER_OPTION_DISABLE_IPV6; + ipv4_only = 0; + } #endif /* Create the secure WebSocket context */ admin_swss = lws_create_vhost(wsc, &info); From fbf106053e3d3d5c84445ac3a6877a1b912b3b9f Mon Sep 17 00:00:00 2001 From: pontscho <32102601+pontscho@users.noreply.github.com> Date: Thu, 25 Mar 2021 17:11:17 +0100 Subject: [PATCH 44/63] Making the timeout parameters for streaming plugin for RTSP play out configurable (#2598) --- conf/janus.plugin.streaming.jcfg.sample.in | 14 +++- plugins/janus_streaming.c | 97 ++++++++++++++++++---- 2 files changed, 93 insertions(+), 18 deletions(-) diff --git a/conf/janus.plugin.streaming.jcfg.sample.in b/conf/janus.plugin.streaming.jcfg.sample.in index 61cad00cb92..fa5c2f43f61 100644 --- a/conf/janus.plugin.streaming.jcfg.sample.in +++ b/conf/janus.plugin.streaming.jcfg.sample.in @@ -78,8 +78,16 @@ # url = RTSP stream URL (only for restreaming RTSP) # rtsp_user = RTSP authorization username (only if type=rtsp) # rtsp_pwd = RTSP authorization password (only if type=rtsp) -# rtspiface = network interface or IP address to bind to, if any (binds to all otherwise), when receiving RTSP streams # rtsp_failcheck = whether an error should be returned if connecting to the RTSP server fails (default=true) +# rtspiface = network interface or IP address to bind to, if any (binds to all otherwise), when receiving RTSP streams +# rtsp_reconnect_delay = after n seconds passed and no media assumed, the RTSP server has gone and schedule a reconnect (default=5s) +# rtsp_session_timeout = by default the streaming plugin will check the RTSP connection with an OPTIONS query, +# the value of the timeout comes from the RTSP session initializer and by default +# this session timeout is the half of this value In some cases this value can be too high (for example more than one minute) +# because of the media server. In that case this plugin will calculate the timeout with this +# formula: timeout = min(session_timeout, rtsp_session_timeout / 2). (default=0s) +# rtsp_timeout = communication timeout (CURLOPT_TIMEOUT) for cURL call gathering the RTSP information (default=10s) +# rtsp_conn_timeout = connection timeout for cURL (CURLOPT_CONNECTTIMEOUT) call gathering the RTSP information (default=5s) # # Notice that, for 'rtsp' mountpoints, normally the plugin uses the exact # SDP rtpmap and fmtp attributes the remote camera or RTSP server sent. @@ -249,4 +257,8 @@ file-ondemand-sample: { #rtsp_user = "username" #rtsp_pwd = "password" #secret = "adminpwd" + #reconnect_delay = 5 + #session_timeout = 0 + # rtsp_timeout = 10 + # rtsp_conn_timeout = 5 #} diff --git a/plugins/janus_streaming.c b/plugins/janus_streaming.c index 8f76e7fec7a..6a04b818db9 100644 --- a/plugins/janus_streaming.c +++ b/plugins/janus_streaming.c @@ -140,6 +140,14 @@ rtsp_user = RTSP authorization username, if needed rtsp_pwd = RTSP authorization password, if needed rtsp_failcheck = whether an error should be returned if connecting to the RTSP server fails (default=true) rtspiface = network interface IP address or device name to listen on when receiving RTSP streams +rtsp_reconnect_delay = after n seconds passed and no media assumed, the RTSP server has gone and schedule a reconnect (default=5s) +rtsp_session_timeout = by default the streaming plugin will check the RTSP connection with an OPTIONS query, + the value of the timeout comes from the RTSP session initializer and by default + this session timeout is the half of this value In some cases this value can be too high (for example more than one minute) + because of the media server. In that case this plugin will calculate the timeout with this + formula: timeout = min(session_timeout, rtsp_session_timeout / 2). (default=0s) +rtsp_timeout = communication timeout (CURLOPT_TIMEOUT) for cURL call gathering the RTSP information (default=10s) +rtsp_conn_timeout = connection timeout for cURL (CURLOPT_CONNECTTIMEOUT) call gathering the RTSP information (default=5s) \endverbatim * * \section streamapi Streaming API @@ -721,6 +729,11 @@ rtspiface = network interface IP address or device name to listen on when receiv #include "../utils.h" #include "../ip-utils.h" +/* Default settings */ +#define JANUS_STREAMING_DEFAULT_SESSION_TIMEOUT 0 /* Overwrite the RTSP session timeout. If set to zero, the RTSP timeout is derived from a session. */ +#define JANUS_STREAMING_DEFAULT_RECONNECT_DELAY 5 /* Reconnecting delay in seconds. */ +#define JANUS_STREAMING_DEFAULT_CURL_TIMEOUT 10L /* Communication timeout for cURL. */ +#define JANUS_STREAMING_DEFAULT_CURL_CONNECT_TIMEOUT 5L /* Connection timeout for cURL. */ /* Plugin information */ #define JANUS_STREAMING_VERSION 8 @@ -855,6 +868,10 @@ static struct janus_json_parameter rtsp_parameters[] = { {"url", JSON_STRING, 0}, {"rtsp_user", JSON_STRING, 0}, {"rtsp_pwd", JSON_STRING, 0}, + {"rtsp_reconnect_delay", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, + {"rtsp_session_timeout", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, + {"rtsp_timeout", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, + {"rtsp_conn_timeout", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, {"audiortpmap", JSON_STRING, 0}, {"audiofmtp", JSON_STRING, 0}, {"audiopt", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, @@ -1066,10 +1083,14 @@ typedef struct janus_streaming_rtp_source { janus_streaming_buffer *curldata; char *rtsp_url; char *rtsp_username, *rtsp_password; - int ka_timeout; + gint64 ka_timeout; char *rtsp_ahost, *rtsp_vhost; gboolean reconnecting; gint64 reconnect_timer; + gint64 reconnect_delay; + gint64 session_timeout; + int rtsp_timeout; + int rtsp_conn_timeout; janus_mutex rtsp_mutex; #endif janus_streaming_rtp_keyframe keyframe; @@ -1188,9 +1209,9 @@ janus_streaming_mountpoint *janus_streaming_create_rtsp_source( gboolean doaudio, int audiopt, char *artpmap, char *afmtp, gboolean dovideo, int videopt, char *vrtpmap, char *vfmtp, gboolean bufferkf, const janus_network_address *iface, int threads, + gint64 reconnect_delay, gint64 session_timeout, int rtsp_timeout, int rtsp_conn_timeout, gboolean error_on_failure); - typedef struct janus_streaming_message { janus_plugin_session *handle; char *transaction; @@ -2101,6 +2122,10 @@ int janus_streaming_init(janus_callbacks *callback, const char *config_path) { janus_config_item *iface = janus_config_get(config, cat, janus_config_type_item, "rtspiface"); janus_config_item *failerr = janus_config_get(config, cat, janus_config_type_item, "rtsp_failcheck"); janus_config_item *threads = janus_config_get(config, cat, janus_config_type_item, "threads"); + janus_config_item *reconnect_delay = janus_config_get(config, cat, janus_config_type_item, "rtsp_reconnect_delay"); + janus_config_item *session_timeout = janus_config_get(config, cat, janus_config_type_item, "rtsp_session_timeout"); + janus_config_item *rtsp_timeout = janus_config_get(config, cat, janus_config_type_item, "rtsp_timeout"); + janus_config_item *rtsp_conn_timeout = janus_config_get(config, cat, janus_config_type_item, "rtsp_conn_timeout"); janus_network_address iface_value; if(file == NULL || file->value == NULL) { JANUS_LOG(LOG_ERR, "Can't add 'rtsp' mountpoint '%s', missing mandatory information...\n", cat->name); @@ -2153,6 +2178,10 @@ int janus_streaming_init(janus_callbacks *callback, const char *config_path) { bufferkf, iface && iface->value ? &iface_value : NULL, (threads && threads->value) ? atoi(threads->value) : 0, + ((reconnect_delay && reconnect_delay->value) ? atoi(reconnect_delay->value) : JANUS_STREAMING_DEFAULT_RECONNECT_DELAY) * G_USEC_PER_SEC, + ((session_timeout && session_timeout->value) ? atoi(session_timeout->value) : JANUS_STREAMING_DEFAULT_SESSION_TIMEOUT) * G_USEC_PER_SEC, + ((rtsp_timeout && rtsp_timeout->value) ? atoi(rtsp_timeout->value) : JANUS_STREAMING_DEFAULT_CURL_TIMEOUT), + ((rtsp_conn_timeout && rtsp_conn_timeout->value) ? atoi(rtsp_conn_timeout->value) : JANUS_STREAMING_DEFAULT_CURL_CONNECT_TIMEOUT), error_on_failure)) == NULL) { JANUS_LOG(LOG_ERR, "Error creating 'rtsp' mountpoint '%s'...\n", cat->name); cl = cl->next; @@ -3162,6 +3191,10 @@ static json_t *janus_streaming_process_synchronous_request(janus_streaming_sessi json_t *iface = json_object_get(root, "rtspiface"); json_t *threads = json_object_get(root, "threads"); json_t *failerr = json_object_get(root, "rtsp_failcheck"); + json_t *reconnect_delay = json_object_get(root, "rtsp_reconnect_delay"); + json_t *session_timeout = json_object_get(root, "rtsp_session_timeout"); + json_t *rtsp_timeout = json_object_get(root, "rtsp_timeout"); + json_t *rtsp_conn_timeout = json_object_get(root, "rtsp_conn_timeout"); if(failerr == NULL) /* For an old typo, we support the legacy syntax too */ failerr = json_object_get(root, "rtsp_check"); gboolean doaudio = audio ? json_is_true(audio) : FALSE; @@ -3205,6 +3238,10 @@ static json_t *janus_streaming_process_synchronous_request(janus_streaming_sessi (char *)json_string_value(videortpmap), (char *)json_string_value(videofmtp), videobufferkf ? json_is_true(videobufferkf) : FALSE, &multicast_iface, (threads ? json_integer_value(threads) : 0), + ((reconnect_delay ? json_integer_value(reconnect_delay) : JANUS_STREAMING_DEFAULT_RECONNECT_DELAY) * G_USEC_PER_SEC), + ((session_timeout ? json_integer_value(session_timeout) : JANUS_STREAMING_DEFAULT_SESSION_TIMEOUT) * G_USEC_PER_SEC), + (rtsp_timeout ? json_integer_value(rtsp_timeout) : JANUS_STREAMING_DEFAULT_CURL_TIMEOUT), + (rtsp_conn_timeout ? json_integer_value(rtsp_conn_timeout) : JANUS_STREAMING_DEFAULT_CURL_CONNECT_TIMEOUT), error_on_failure); janus_mutex_lock(&mountpoints_mutex); g_hash_table_remove(mountpoints_temp, string_ids ? (gpointer)mpid_str : (gpointer)&mpid); @@ -5598,7 +5635,7 @@ static int janus_streaming_allocate_port_pair(const char *name, const char *medi static int janus_streaming_get_fd_port(int fd) { struct sockaddr_in6 server = { 0 }; socklen_t len = sizeof(server); - if(getsockname(fd, &server, &len) == -1) { + if(getsockname(fd, (struct sockaddr *)&server, &len) == -1) { return -1; } @@ -6328,6 +6365,11 @@ static int janus_streaming_rtsp_parse_sdp(const char *buffer, const char *name, return 0; } +/* Helper function to calculating the minimum value if 'a' is bigger than zero */ +static inline gint64 janus_streaming_min_if(gint64 a, gint64 b) { + return a > 0 ? (a > b ? b : a) : b; +} + /* Static helper to connect to an RTSP server, considering we might do this either * when creating a new mountpoint, or when reconnecting after some failure */ static int janus_streaming_rtsp_connect_to_server(janus_streaming_mountpoint *mp) { @@ -6350,8 +6392,8 @@ static int janus_streaming_rtsp_connect_to_server(janus_streaming_mountpoint *mp curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); curl_easy_setopt(curl, CURLOPT_URL, source->rtsp_url); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 5L); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, source->rtsp_timeout); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, source->rtsp_conn_timeout); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 0L); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); #if CURL_AT_LEAST_VERSION(7, 66, 0) @@ -6403,7 +6445,6 @@ static int janus_streaming_rtsp_connect_to_server(janus_streaming_mountpoint *mp } JANUS_LOG(LOG_VERB, "DESCRIBE answer:%s\n", curldata->buffer); /* Parse the SDP we just got to figure out the negotiated media */ - int ka_timeout = 0; int vpt = -1; char vrtpmap[2048]; vrtpmap[0] = '\0'; @@ -6574,8 +6615,8 @@ static int janus_streaming_rtsp_connect_to_server(janus_streaming_mountpoint *mp } else if(is_session) { if(!strcasecmp(name, "timeout")) { /* Take note of the timeout, for keep-alives */ - ka_timeout = atoi(value); - JANUS_LOG(LOG_VERB, " -- RTSP session timeout (video): %d\n", ka_timeout); + source->ka_timeout = janus_streaming_min_if(source->session_timeout, atoi(value) / 2 * G_USEC_PER_SEC); + JANUS_LOG(LOG_VERB, " -- RTSP session timeout (video): %"SCNi64" ms\n", source->ka_timeout / 1000); } } } @@ -6747,8 +6788,8 @@ static int janus_streaming_rtsp_connect_to_server(janus_streaming_mountpoint *mp } else if(is_session) { if(!strcasecmp(name, "timeout")) { /* Take note of the timeout, for keep-alives */ - ka_timeout = atoi(value); - JANUS_LOG(LOG_VERB, " -- RTSP session timeout (audio): %d\n", ka_timeout); + source->ka_timeout = janus_streaming_min_if(source->session_timeout, atoi(value) / 2 * G_USEC_PER_SEC); + JANUS_LOG(LOG_VERB, " -- RTSP session timeout (audio): %"SCNi64" ms\n", source->ka_timeout / 1000); } } } @@ -6850,7 +6891,6 @@ static int janus_streaming_rtsp_connect_to_server(janus_streaming_mountpoint *mp source->rtsp_vhost = g_strdup(vhost); source->curl = curl; source->curldata = curldata; - source->ka_timeout = ka_timeout; return 0; } @@ -6951,6 +6991,7 @@ janus_streaming_mountpoint *janus_streaming_create_rtsp_source( gboolean doaudio, int acodec, char *artpmap, char *afmtp, gboolean dovideo, int vcodec, char *vrtpmap, char *vfmtp, gboolean bufferkf, const janus_network_address *iface, int threads, + gint64 reconnect_delay, gint64 session_timeout, int rtsp_timeout, int rtsp_conn_timeout, gboolean error_on_failure) { char id_num[30]; if(!string_ids) { @@ -6961,6 +7002,23 @@ janus_streaming_mountpoint *janus_streaming_create_rtsp_source( JANUS_LOG(LOG_ERR, "Can't add 'rtsp' stream, missing url...\n"); return NULL; } + if(reconnect_delay < 0) { + JANUS_LOG(LOG_ERR, "rtsp_reconnect_delay can't be smaller than zero.\n"); + return NULL; + } + if(session_timeout < 0) { + JANUS_LOG(LOG_ERR, "rtsp_session_timeout can't be smaller than zero.\n"); + return NULL; + } + if(rtsp_timeout < 0) { + JANUS_LOG(LOG_ERR, "rtsp_timeout can't be smaller than zero.\n"); + return NULL; + } + if(rtsp_conn_timeout < 0) { + JANUS_LOG(LOG_ERR, "rtsp_conn_timeout can't be smaller than zero.\n"); + return NULL; + } + JANUS_LOG(LOG_VERB, "Audio %s, Video %s\n", doaudio ? "enabled" : "NOT enabled", dovideo ? "enabled" : "NOT enabled"); /* Create an RTP source for the media we'll get */ @@ -7025,6 +7083,11 @@ janus_streaming_mountpoint *janus_streaming_create_rtsp_source( live_rtsp_source->keyframe.latest_keyframe = NULL; live_rtsp_source->keyframe.temp_keyframe = NULL; live_rtsp_source->keyframe.temp_ts = 0; + live_rtsp_source->ka_timeout = session_timeout; + live_rtsp_source->reconnect_delay = reconnect_delay; + live_rtsp_source->session_timeout = session_timeout; + live_rtsp_source->rtsp_timeout = rtsp_timeout; + live_rtsp_source->rtsp_conn_timeout = rtsp_conn_timeout; janus_mutex_init(&live_rtsp_source->keyframe.mutex); live_rtsp_source->reconnect_timer = 0; janus_mutex_init(&live_rtsp_source->rtsp_mutex); @@ -7130,6 +7193,7 @@ janus_streaming_mountpoint *janus_streaming_create_rtsp_source( gboolean doaudio, int acodec, char *audiortpmap, char *audiofmtp, gboolean dovideo, int vcodec, char *videortpmap, char *videofmtp, gboolean bufferkf, const janus_network_address *iface, int threads, + gint64 reconnect_delay, gint64 session_timeout, int rtsp_timeout, int rtsp_conn_timeout, gboolean error_on_failure) { JANUS_LOG(LOG_ERR, "RTSP need libcurl\n"); return NULL; @@ -7503,7 +7567,7 @@ static void *janus_streaming_relay_thread(void *data) { gint64 now = janus_get_monotonic_time(), before = now, ka_timeout = 0; if(source->rtsp) { source->reconnect_timer = now; - ka_timeout = ((gint64)source->ka_timeout*G_USEC_PER_SEC)/2; + ka_timeout = source->ka_timeout; } #endif /* Loop */ @@ -7519,8 +7583,8 @@ static void *janus_streaming_relay_thread(void *data) { continue; } now = janus_get_monotonic_time(); - if(!source->reconnecting && (now - source->reconnect_timer > 5*G_USEC_PER_SEC)) { - /* 5 seconds passed and no media? Assume the RTSP server has gone and schedule a reconnect */ + if(!source->reconnecting && (now - source->reconnect_timer > source->reconnect_delay)) { + /* Assume the RTSP server has gone and schedule a reconnect */ JANUS_LOG(LOG_WARN, "[%s] %"SCNi64"s passed with no media, trying to reconnect the RTSP stream\n", name, (now - source->reconnect_timer)/G_USEC_PER_SEC); audio_fd = -1; @@ -7582,7 +7646,7 @@ static void *janus_streaming_relay_thread(void *data) { data_fd = source->data_fd; audio_rtcp_fd = source->audio_rtcp_fd; video_rtcp_fd = source->video_rtcp_fd; - ka_timeout = ((gint64)source->ka_timeout*G_USEC_PER_SEC)/2; + ka_timeout = source->ka_timeout; } } source->reconnect_timer = janus_get_monotonic_time(); @@ -7592,7 +7656,7 @@ static void *janus_streaming_relay_thread(void *data) { } if(audio_fd < 0 && video_fd[0] < 0 && video_fd[1] < 0 && video_fd[2] < 0 && data_fd < 0) { /* No socket, we may be in the process of reconnecting, or waiting to reconnect */ - g_usleep(5000000); + g_usleep(source->reconnect_delay); continue; } /* We may also need to occasionally send a OPTIONS request as a keep-alive */ @@ -8485,7 +8549,6 @@ static void janus_streaming_relay_rtp_packet(gpointer data, gpointer user_data) return; } - static void janus_streaming_relay_rtcp_packet(gpointer data, gpointer user_data) { janus_streaming_rtp_relay_packet *packet = (janus_streaming_rtp_relay_packet *)user_data; if(!packet || !packet->data || packet->length < 1) { From 08f44122590481b27c52dee941fc7ea47d5c1ce3 Mon Sep 17 00:00:00 2001 From: Evgeniy Baranov Date: Tue, 30 Mar 2021 12:20:48 +0300 Subject: [PATCH 45/63] fix memory leak in turnrest (#2606) --- turnrest.c | 1 + 1 file changed, 1 insertion(+) diff --git a/turnrest.c b/turnrest.c index 797ed184d32..e6f45920b09 100644 --- a/turnrest.c +++ b/turnrest.c @@ -117,6 +117,7 @@ void janus_turnrest_response_destroy(janus_turnrest_response *response) { g_free(response->username); g_free(response->password); g_list_free_full(response->servers, janus_turnrest_instance_destroy); + g_free(response); } janus_turnrest_response *janus_turnrest_request(const char *user) { From 82e1b93829ca8da043a2b55d9ddad5610b279a77 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 30 Mar 2021 11:41:30 +0200 Subject: [PATCH 46/63] Fixed broken path parsing in WebSocket event handler (fixes #2603) --- events/janus_wsevh.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/events/janus_wsevh.c b/events/janus_wsevh.c index 6607a27185b..f169b22ace1 100644 --- a/events/janus_wsevh.c +++ b/events/janus_wsevh.c @@ -107,7 +107,8 @@ static struct janus_json_parameter tweak_parameters[] = { /* WebSockets properties */ static char *backend = NULL; -static const char *protocol = NULL, *address = NULL, *path = NULL; +static const char *protocol = NULL, *address = NULL; +static char path[256]; static int port = 0; static struct lws_context *context = NULL; static gint64 disconnected = 0; @@ -261,7 +262,8 @@ int janus_wsevh_init(const char *config_path) { JANUS_LOG(LOG_FATAL, "Missing WebSockets backend\n"); goto error; } - if(lws_parse_uri(backend, &protocol, &address, &port, &path)) { + const char *p = NULL; + if(lws_parse_uri(backend, &protocol, &address, &port, &p)) { JANUS_LOG(LOG_FATAL, "Error parsing address\n"); goto error; } @@ -269,9 +271,12 @@ int janus_wsevh_init(const char *config_path) { JANUS_LOG(LOG_FATAL, "Invalid address (only ws:// addresses are supported)\n"); JANUS_LOG(LOG_FATAL, " -- Protocol: %s\n", protocol); JANUS_LOG(LOG_FATAL, " -- Address: %s\n", address); - JANUS_LOG(LOG_FATAL, " -- Path: %s\n", path); + JANUS_LOG(LOG_FATAL, " -- Path: %s\n", p); goto error; } + path[0] = '/'; + if(strlen(p) > 1) + g_strlcpy(path + 1, p, sizeof(path)-2); /* Before connecting, let's check if the server expects a subprotocol */ item = janus_config_get(config, config_general, janus_config_type_item, "subprotocol"); if(item && item->value) From cfc40476e6ed0fdbc9fbe94729de29088e8790fd Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 30 Mar 2021 12:04:39 +0200 Subject: [PATCH 47/63] Added wss and debugging support to WebSocket event handler --- conf/janus.eventhandler.wsevh.jcfg.sample | 13 ++- events/janus_wsevh.c | 106 ++++++++++++++++++++-- 2 files changed, 106 insertions(+), 13 deletions(-) diff --git a/conf/janus.eventhandler.wsevh.jcfg.sample b/conf/janus.eventhandler.wsevh.jcfg.sample index 38f22ff0681..c5cc364ca43 100644 --- a/conf/janus.eventhandler.wsevh.jcfg.sample +++ b/conf/janus.eventhandler.wsevh.jcfg.sample @@ -14,13 +14,18 @@ general: { # (one or more per HTTP POST, JSON array with objects) # The default is 'yes' to limit the number of connections. - # Address the plugin will send all events to as HTTP POST - # requests with an application/json payload. In case - # authentication is required to contact the backend, set - # the credentials as well (basic authentication only). json = "indented" # Whether the JSON messages should be indented (default), # plain (no indentation) or compact (no indentation and no spaces) + # Address the plugin will send all events to as WebSocket + # messages. In case authentication is required to contact + # the backend, set the credentials as well. backend = "ws://your.websocket.here" # subprotocol = "your-subprotocol" + + # In case you need to debug connection issues, you can configure + # the libwebsockets debugging level as a comma separated list of things + # to debug, supported values: err, warn, notice, info, debug, parser, + # header, ext, client, latency, user, count (plus 'none' and 'all') + #ws_logging = "err,warn" } diff --git a/events/janus_wsevh.c b/events/janus_wsevh.c index f169b22ace1..f0eb16f3507 100644 --- a/events/janus_wsevh.c +++ b/events/janus_wsevh.c @@ -104,6 +104,45 @@ static struct janus_json_parameter tweak_parameters[] = { #define JANUS_WSEVH_ERROR_INVALID_ELEMENT 413 #define JANUS_WSEVH_ERROR_UNKNOWN_ERROR 499 +/* Logging */ +static int wsevh_log_level = 0; +static const char *janus_wsevh_get_level_str(int level) { + switch(level) { + case LLL_ERR: + return "ERR"; + case LLL_WARN: + return "WARN"; + case LLL_NOTICE: + return "NOTICE"; + case LLL_INFO: + return "INFO"; + case LLL_DEBUG: + return "DEBUG"; + case LLL_PARSER: + return "PARSER"; + case LLL_HEADER: + return "HEADER"; + case LLL_EXT: + return "EXT"; + case LLL_CLIENT: + return "CLIENT"; + case LLL_LATENCY: + return "LATENCY"; +#if (LWS_LIBRARY_VERSION_MAJOR >= 2 && LWS_LIBRARY_VERSION_MINOR >= 2) || (LWS_LIBRARY_VERSION_MAJOR >= 3) + case LLL_USER: + return "USER"; +#endif + case LLL_COUNT: + return "COUNT"; + default: + return NULL; + } +} +static void janus_wsevh_log_emit_function(int level, const char *line) { + /* FIXME Do we want to use different Janus debug levels according to the level here? */ + JANUS_LOG(LOG_INFO, "[libwebsockets][wsevh][%s] %s", janus_wsevh_get_level_str(level), line); +} + /* WebSockets properties */ static char *backend = NULL; @@ -244,6 +283,55 @@ int janus_wsevh_init(const char *config_path) { } } + item = janus_config_get(config, config_general, janus_config_type_item, "ws_logging"); + if(item && item->value) { + /* libwebsockets uses a mask to set log levels, as documented here: + * https://libwebsockets.org/lws-api-doc-master/html/group__log.html */ + if(strstr(item->value, "none")) { + /* Disable libwebsockets logging completely (the default) */ + } else if(strstr(item->value, "all")) { + /* Enable all libwebsockets logging */ + wsevh_log_level = LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO | + LLL_DEBUG | LLL_PARSER | LLL_HEADER | LLL_EXT | +#if (LWS_LIBRARY_VERSION_MAJOR >= 2 && LWS_LIBRARY_VERSION_MINOR >= 2) || (LWS_LIBRARY_VERSION_MAJOR >= 3) + LLL_CLIENT | LLL_LATENCY | LLL_USER | LLL_COUNT; +#else + LLL_CLIENT | LLL_LATENCY | LLL_COUNT; +#endif + } else { + /* Only enable some of the properties */ + if(strstr(item->value, "err")) + wsevh_log_level |= LLL_ERR; + if(strstr(item->value, "warn")) + wsevh_log_level |= LLL_WARN; + if(strstr(item->value, "notice")) + wsevh_log_level |= LLL_NOTICE; + if(strstr(item->value, "info")) + wsevh_log_level |= LLL_INFO; + if(strstr(item->value, "debug")) + wsevh_log_level |= LLL_DEBUG; + if(strstr(item->value, "parser")) + wsevh_log_level |= LLL_PARSER; + if(strstr(item->value, "header")) + wsevh_log_level |= LLL_HEADER; + if(strstr(item->value, "ext")) + wsevh_log_level |= LLL_EXT; + if(strstr(item->value, "client")) + wsevh_log_level |= LLL_CLIENT; + if(strstr(item->value, "latency")) + wsevh_log_level |= LLL_LATENCY; +#if (LWS_LIBRARY_VERSION_MAJOR >= 2 && LWS_LIBRARY_VERSION_MINOR >= 2) || (LWS_LIBRARY_VERSION_MAJOR >= 3) + if(strstr(item->value, "user")) + wsevh_log_level |= LLL_USER; +#endif + if(strstr(item->value, "count")) + wsevh_log_level |= LLL_COUNT; + } + } + if(wsevh_log_level > 0) + JANUS_LOG(LOG_INFO, "WebSockets event handler libwebsockets logging: %d\n", wsevh_log_level); + lws_set_log_level(wsevh_log_level, janus_wsevh_log_emit_function); + /* Which events should we subscribe to? */ item = janus_config_get(config, config_general, janus_config_type_item, "events"); if(item && item->value) @@ -267,8 +355,8 @@ int janus_wsevh_init(const char *config_path) { JANUS_LOG(LOG_FATAL, "Error parsing address\n"); goto error; } - if(strcasecmp(protocol, "ws") || !strlen(address)) { - JANUS_LOG(LOG_FATAL, "Invalid address (only ws:// addresses are supported)\n"); + if((strcasecmp(protocol, "ws") && strcasecmp(protocol, "wss")) || !strlen(address)) { + JANUS_LOG(LOG_FATAL, "Invalid address (only ws:// and wss:// addresses are supported)\n"); JANUS_LOG(LOG_FATAL, " -- Protocol: %s\n", protocol); JANUS_LOG(LOG_FATAL, " -- Address: %s\n", address); JANUS_LOG(LOG_FATAL, " -- Path: %s\n", p); @@ -284,31 +372,31 @@ int janus_wsevh_init(const char *config_path) { /* Connect */ JANUS_LOG(LOG_VERB, "WebSocketsEventHandler: Connecting to WebSockets server...\n"); - struct lws_context_creation_info info; - memset(&info, 0, sizeof(info)); + gboolean secure = !strcasecmp(protocol, "wss"); + struct lws_context_creation_info info = { 0 }; info.port = CONTEXT_PORT_NO_LISTEN; info.protocols = protocols; info.gid = -1; info.uid = -1; - info.options = 0; + if(secure) + info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; context = lws_create_context(&info); if(context == NULL) { JANUS_LOG(LOG_FATAL, "Creating libwebsocket context failed\n"); goto error; } - struct lws_client_connect_info i; - memset(&i, 0, sizeof(i)); + struct lws_client_connect_info i = { 0 }; i.host = address; i.origin = address; i.address = address; i.port = port; i.path = path; i.context = context; - i.ssl_connection = 0; + if(secure) + i.ssl_connection = 1; i.ietf_version_or_minus_one = -1; i.client_exts = exts; i.protocol = protocols[0].name; - i.method = NULL; wsi = lws_client_connect_via_info(&i); if(wsi == NULL) { JANUS_LOG(LOG_FATAL, "Error initializing WebSocket connection\n"); From 9ef4606c4f86684ab3429599c281a5fd61203cf7 Mon Sep 17 00:00:00 2001 From: Tijmen de Mes Date: Tue, 30 Mar 2021 12:35:49 +0200 Subject: [PATCH 48/63] Fixed sending responses from Janus for incoming SIP MESSAGE/SIP INFO (#2609) --- plugins/janus_sip.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/plugins/janus_sip.c b/plugins/janus_sip.c index a1c0d3c98ef..84d79937003 100644 --- a/plugins/janus_sip.c +++ b/plugins/janus_sip.c @@ -5083,8 +5083,6 @@ void janus_sip_sofia_callback(nua_event_t event, int status, char const *phrase, JANUS_LOG(LOG_VERB, "[%s][%s]: %d %s\n", session->account.username, nua_event_name(event), status, phrase ? phrase : "??"); /* We expect a payload */ if(!sip->sip_content_type || !sip->sip_content_type->c_type || !sip->sip_payload || !sip->sip_payload->pl_data) { - nua_respond(nh, 488, sip_status_phrase(488), - NUTAG_WITH_CURRENT(nua), TAG_END()); return; } const char *type = sip->sip_content_type->c_type; @@ -5112,17 +5110,12 @@ void janus_sip_sofia_callback(nua_event_t event, int status, char const *phrase, int ret = gateway->push_event(session->handle, &janus_sip_plugin, session->transaction, info, NULL); JANUS_LOG(LOG_VERB, " >> Pushing event to peer: %d (%s)\n", ret, janus_get_api_error(ret)); json_decref(info); - /* Send a 200 back */ - nua_respond(nh, 200, sip_status_phrase(200), - NUTAG_WITH_CURRENT(nua), TAG_END()); break; } case nua_i_message: { JANUS_LOG(LOG_VERB, "[%s][%s]: %d %s\n", session->account.username, nua_event_name(event), status, phrase ? phrase : "??"); /* We expect a payload */ if(!sip->sip_content_type || !sip->sip_content_type->c_type || !sip->sip_payload || !sip->sip_payload->pl_data) { - nua_respond(nh, 488, sip_status_phrase(488), - NUTAG_WITH_CURRENT(nua), TAG_END()); return; } const char *content_type = sip->sip_content_type->c_type; @@ -5150,9 +5143,6 @@ void janus_sip_sofia_callback(nua_event_t event, int status, char const *phrase, int ret = gateway->push_event(session->handle, &janus_sip_plugin, session->transaction, message, NULL); JANUS_LOG(LOG_VERB, " >> Pushing event to peer: %d (%s)\n", ret, janus_get_api_error(ret)); json_decref(message); - /* Send a 200 back */ - nua_respond(nh, 200, sip_status_phrase(200), - NUTAG_WITH_CURRENT(nua), TAG_END()); break; } case nua_i_notify: { From 2002b7b2be54f3e81530d82ca10e4d4b9d7902b4 Mon Sep 17 00:00:00 2001 From: Sergey Radionov Date: Tue, 30 Mar 2021 23:25:09 +0700 Subject: [PATCH 49/63] audiobridge: GList leak fixed (#2611) --- plugins/janus_audiobridge.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/janus_audiobridge.c b/plugins/janus_audiobridge.c index 763c8d96ba3..01e7b5a249d 100644 --- a/plugins/janus_audiobridge.c +++ b/plugins/janus_audiobridge.c @@ -6663,6 +6663,7 @@ static void *janus_audiobridge_mixer_thread(void *data) { } ps = ps->next; } + g_list_free(anncs_list); } #endif /* Are we recording the mix? (only do it if there's someone in, though...) */ From 7f054c03ab54edec6aab4045fc9f2bfdc817da83 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Wed, 31 Mar 2021 11:41:53 +0200 Subject: [PATCH 50/63] Initialize simulcast RTCP contexts even if SSRCs are missing (fixes #2610) --- sdp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdp.c b/sdp.c index 7d4e443ca3d..5b68ece9937 100644 --- a/sdp.c +++ b/sdp.c @@ -640,11 +640,11 @@ int janus_sdp_process(void *ice_handle, janus_sdp *remote_sdp, gboolean rids_hml stream->video_ssrc_rtx = janus_random_uint32(); /* FIXME Should we look for conflicts? */ } } - if(stream->video_ssrc_peer[1] && stream->video_rtcp_ctx[1] == NULL) { + if((stream->video_ssrc_peer[1] || stream->rid[1] != NULL) && stream->video_rtcp_ctx[1] == NULL) { stream->video_rtcp_ctx[1] = g_malloc0(sizeof(rtcp_context)); stream->video_rtcp_ctx[1]->tb = 90000; } - if(stream->video_ssrc_peer[2] && stream->video_rtcp_ctx[2] == NULL) { + if((stream->video_ssrc_peer[2] || stream->rid[rids_hml ? 2 : 0] != NULL) && stream->video_rtcp_ctx[2] == NULL) { stream->video_rtcp_ctx[2] = g_malloc0(sizeof(rtcp_context)); stream->video_rtcp_ctx[2]->tb = 90000; } From de846866cee5aa48f11205de8a4ea99e8fc571e0 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Wed, 31 Mar 2021 11:48:45 +0200 Subject: [PATCH 51/63] Added session timeout value to Admin API info --- janus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/janus.c b/janus.c index ea2b1f56e8b..77965af98c8 100644 --- a/janus.c +++ b/janus.c @@ -2825,6 +2825,7 @@ int janus_process_incoming_admin_request(janus_request *request) { json_t *info = json_object(); json_object_set_new(info, "session_id", json_integer(session_id)); json_object_set_new(info, "session_last_activity", json_integer(session->last_activity)); + json_object_set_new(info, "session_timeout", json_integer(session->timeout == -1 ? global_session_timeout : (guint)session->timeout)); janus_mutex_lock(&session->mutex); if(session->source && session->source->transport) json_object_set_new(info, "session_transport", json_string(session->source->transport->get_package())); From 34129a958ded21b4569386830659b7e3cbbb37d1 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Wed, 31 Mar 2021 12:09:28 +0200 Subject: [PATCH 52/63] Added new video (SIP/Janus workshop) to the documentation --- mainpage.dox | 1 + 1 file changed, 1 insertion(+) diff --git a/mainpage.dox b/mainpage.dox index eb909a7a911..39a3322964b 100644 --- a/mainpage.dox +++ b/mainpage.dox @@ -3928,6 +3928,7 @@ ldd janus | grep asan * - Presentation on using Janus for Virtual Events at CommCon 2020; * - Workshop on Janus (lesson/tutorial) at ClueCon 2020; * - Presentation on E2EE (end-to-end encryption) and Insertable Streams at ClueCon 2020; + * - Workshop on Janus and SIP at OpenSIPS 2020; * - Presentation on SFUs and MCUs at IIT RTC 2020; * - Presentation on using Janus for IETF Virtual Participation at the MOPS WG session (IETF109); * - Presentation on WebRTC (and Janus) as a way to help musicians at FOSDEM 2021; From a85e7630b83edffece1db1a53b089a4749e090ec Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Wed, 31 Mar 2021 12:10:18 +0200 Subject: [PATCH 53/63] Fixed typo --- mainpage.dox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mainpage.dox b/mainpage.dox index 39a3322964b..a67602e8e81 100644 --- a/mainpage.dox +++ b/mainpage.dox @@ -3928,7 +3928,7 @@ ldd janus | grep asan * - Presentation on using Janus for Virtual Events at CommCon 2020; * - Workshop on Janus (lesson/tutorial) at ClueCon 2020; * - Presentation on E2EE (end-to-end encryption) and Insertable Streams at ClueCon 2020; - * - Workshop on Janus and SIP at OpenSIPS 2020; + * - Workshop on Janus and SIP (lesson/tutorial) at OpenSIPS 2020; * - Presentation on SFUs and MCUs at IIT RTC 2020; * - Presentation on using Janus for IETF Virtual Participation at the MOPS WG session (IETF109); * - Presentation on WebRTC (and Janus) as a way to help musicians at FOSDEM 2021; From bed081c03ad4854f3956898646198100a8ed82cf Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Thu, 1 Apr 2021 16:39:37 +0200 Subject: [PATCH 54/63] Add substream to audio/video receiving events (fixes #2615) --- ice.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/ice.c b/ice.c index 14d992760ec..09bffdf1a03 100644 --- a/ice.c +++ b/ice.c @@ -718,7 +718,7 @@ static void janus_ice_notify_trickle(janus_ice_handle *handle, char *buffer) { janus_session_notify_event(session, event); } -static void janus_ice_notify_media(janus_ice_handle *handle, gboolean video, gboolean up) { +static void janus_ice_notify_media(janus_ice_handle *handle, gboolean video, int substream, gboolean up) { if(handle == NULL) return; /* Prepare JSON event to notify user/application */ @@ -734,6 +734,8 @@ static void janus_ice_notify_media(janus_ice_handle *handle, gboolean video, gbo if(opaqueid_in_api && handle->opaque_id != NULL) json_object_set_new(event, "opaque_id", json_string(handle->opaque_id)); json_object_set_new(event, "type", json_string(video ? "video" : "audio")); + if(video && handle->stream && handle->stream->video_rtcp_ctx[1] != NULL) + json_object_set_new(event, "substream", json_integer(substream)); json_object_set_new(event, "receiving", up ? json_true() : json_false()); if(!up && no_media_timer > 1) json_object_set_new(event, "seconds", json_integer(no_media_timer)); @@ -744,6 +746,8 @@ static void janus_ice_notify_media(janus_ice_handle *handle, gboolean video, gbo if(janus_events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "media", json_string(video ? "video" : "audio")); + if(video && handle->stream && handle->stream->video_rtcp_ctx[1] != NULL) + json_object_set_new(info, "substream", json_integer(substream)); json_object_set_new(info, "receiving", up ? json_true() : json_false()); if(!up && no_media_timer > 1) json_object_set_new(info, "seconds", json_integer(no_media_timer)); @@ -2671,7 +2675,7 @@ static void janus_ice_cb_nice_recv(NiceAgent *agent, guint stream_id, guint comp if(component->in_stats.audio.bytes == 0 || component->in_stats.audio.notified_lastsec) { /* We either received our first audio packet, or we started receiving it again after missing more than a second */ component->in_stats.audio.notified_lastsec = FALSE; - janus_ice_notify_media(handle, FALSE, TRUE); + janus_ice_notify_media(handle, FALSE, 0, TRUE); } /* Overall audio data */ component->in_stats.audio.packets++; @@ -2690,7 +2694,7 @@ static void janus_ice_cb_nice_recv(NiceAgent *agent, guint stream_id, guint comp if(component->in_stats.video[vindex].bytes == 0 || component->in_stats.video[vindex].notified_lastsec) { /* We either received our first video packet, or we started receiving it again after missing more than a second */ component->in_stats.video[vindex].notified_lastsec = FALSE; - janus_ice_notify_media(handle, TRUE, TRUE); + janus_ice_notify_media(handle, TRUE, vindex, TRUE); } /* Overall video data for this SSRC */ component->in_stats.video[vindex].packets++; @@ -4091,17 +4095,20 @@ static gboolean janus_ice_outgoing_stats_handle(gpointer user_data) { /* We missed more than no_second_timer seconds of audio! */ component->in_stats.audio.notified_lastsec = TRUE; JANUS_LOG(LOG_WARN, "[%"SCNu64"] Didn't receive audio for more than %d seconds...\n", handle->handle_id, no_media_timer); - janus_ice_notify_media(handle, FALSE, FALSE); + janus_ice_notify_media(handle, FALSE, 0, FALSE); } /* Video */ - last = component->in_stats.video[0].updated; - if(!component->in_stats.video[0].notified_lastsec && last && - !component->in_stats.video[0].bytes_lastsec && !component->in_stats.video[0].bytes_lastsec_temp && - now-last >= (gint64)no_media_timer*G_USEC_PER_SEC) { - /* We missed more than no_second_timer seconds of video! */ - component->in_stats.video[0].notified_lastsec = TRUE; - JANUS_LOG(LOG_WARN, "[%"SCNu64"] Didn't receive video for more than a second...\n", handle->handle_id); - janus_ice_notify_media(handle, TRUE, FALSE); + int vindex=0; + for(vindex=0; vindex<3; vindex++) { + last = component->in_stats.video[vindex].updated; + if(!component->in_stats.video[vindex].notified_lastsec && last && + !component->in_stats.video[vindex].bytes_lastsec && !component->in_stats.video[vindex].bytes_lastsec_temp && + now-last >= (gint64)no_media_timer*G_USEC_PER_SEC) { + /* We missed more than no_second_timer seconds of this video stream! */ + component->in_stats.video[vindex].notified_lastsec = TRUE; + JANUS_LOG(LOG_WARN, "[%"SCNu64"] Didn't receive video #%d for more than a second...\n", handle->handle_id, vindex); + janus_ice_notify_media(handle, TRUE, vindex, FALSE); + } } } /* We also send live stats to event handlers every tot-seconds (configurable) */ From 9bf29f9752bc3b97d2da8ed3db5f016e50c98401 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Fri, 2 Apr 2021 14:18:06 +0200 Subject: [PATCH 55/63] Added extra reference to VideoRoom --- plugins/janus_videoroom.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index cde42748993..1d72f82f1db 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -5826,6 +5826,7 @@ static void janus_videoroom_hangup_media_internal(gpointer session_data) { is in this function and accessing to this function is synchronized by sessions_mutex */ if(publisher != NULL) { + janus_refcount_increase(&publisher->ref); /* Also notify event handlers */ if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); @@ -5838,6 +5839,7 @@ static void janus_videoroom_hangup_media_internal(gpointer session_data) { publisher->subscribers = g_slist_remove(publisher->subscribers, subscriber); janus_videoroom_hangup_subscriber(subscriber); janus_mutex_unlock(&publisher->subscribers_mutex); + janus_refcount_decrease(&publisher->ref); } subscriber->e2ee = FALSE; } From 4dd379ab6952ccaaa027d5c150da1fbf0fecff16 Mon Sep 17 00:00:00 2001 From: Massimiliano Torromeo Date: Fri, 2 Apr 2021 17:40:05 +0200 Subject: [PATCH 56/63] Added new --log-stdout flag that enabled stdout logging even when daemonizing the process (#2591) --- janus.1 | 3 +++ janus.c | 8 ++------ janus.ggo | 1 + log.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/janus.1 b/janus.1 index 5eae19edd7f..ad3b36f652d 100644 --- a/janus.1 +++ b/janus.1 @@ -26,6 +26,9 @@ Open the specified PID file when starting Janus (default=none) .BR \-N ", " \-\-disable-stdout Disable stdout based logging (default=off) .TP +.BR \-L ", " \-\-log-stdout +Log to stdout, even when the process is daemonized (default=off) +.TP .BR \-L ", " \-\-log-file=\fIpath\fR Log to the specified file (default=stdout only) .TP diff --git a/janus.c b/janus.c index 77965af98c8..149585fb5c1 100644 --- a/janus.c +++ b/janus.c @@ -4119,7 +4119,7 @@ gint main(int argc, char *argv[]) if(args_info.disable_stdout_given) { use_stdout = FALSE; janus_config_add(config, config_general, janus_config_item_create("log_to_stdout", "no")); - } else { + } else if(!args_info.log_stdout_given) { /* Check if the configuration file is saying anything about this */ janus_config_item *item = janus_config_get(config, config_general, janus_config_type_item, "log_to_stdout"); if(item && item->value && !janus_is_true(item->value)) @@ -4147,13 +4147,9 @@ gint main(int argc, char *argv[]) daemonize = TRUE; } /* If we're going to daemonize, make sure logging to stdout is disabled and a log file has been specified */ - if(daemonize && use_stdout) { + if(daemonize && use_stdout && !args_info.log_stdout_given) { use_stdout = FALSE; } - if(daemonize && logfile == NULL) { - g_print("Running Janus as a daemon but no log file provided, giving up...\n"); - exit(1); - } /* Daemonize now, if we need to */ if(daemonize) { g_print("Running Janus as a daemon\n"); diff --git a/janus.ggo b/janus.ggo index fa8b157b6ca..cc5b1318bb0 100644 --- a/janus.ggo +++ b/janus.ggo @@ -2,6 +2,7 @@ option "daemon" b "Launch Janus in background as a daemon" flag off option "pid-file" p "Open the specified PID file when starting Janus (default=none)" string typestr="path" optional option "disable-stdout" N "Disable stdout based logging" flag off +option "log-stdout" - "Log to stdout, even when the process is daemonized" flag off option "log-file" L "Log to the specified file (default=stdout only)" string typestr="path" optional option "cwd-path" H "Working directory for Janus daemon process (default=/)" string typestr="path" optional option "interface" i "Interface to use (will be the public IP)" string typestr="ipaddress" optional diff --git a/log.c b/log.c index e1934bb781b..f9003cb90b8 100644 --- a/log.c +++ b/log.c @@ -239,7 +239,7 @@ int janus_log_init(gboolean daemon, gboolean console, const char *logfile) { g_print("WARNING: logging completely disabled!\n"); g_print(" (no stdout and no logfile, this may not be what you want...)\n"); } - if(daemon) { + if(daemon && !console) { /* Replace the standard file descriptors */ if (freopen("/dev/null", "r", stdin) == NULL) { g_print("Error replacing stdin with /dev/null\n"); From d8ec8e0ea0ae34f333f6beb3675b102ad9ef17a3 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 6 Apr 2021 12:31:02 +0200 Subject: [PATCH 57/63] Updated Changelog (0.11.0) --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55d77fe5b7a..19e574301d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,24 @@ All notable changes to this project will be documented in this file. +## [v0.11.0] - 2021-04-06 + +- Add new option to configure ICE nomination mode, if libnice is recent enough [[PR-2541](#2541)] +- Added support for per-session timeout values (thanks @alg!) [[PR-2577](#2577)] +- Added support for compilation on FreeBSD (thanks @jsm222!) [[PR-2508](#2508)] +- Fixed occasional auth errors when using both API secret and stored tokens (thanks @deep9!) [[PR-2581](#2581)] +- Added support for stdout logging to daemon-mode as well (thanks @mtorromeo!) [[PR-2591](#2591)] +- Fixed odr-violation issue between Lua and Duktape plugins [[PR-2540](#2540)] +- Fixed missing simulcast stats in Admin API and Event Handlers when using rid [[Issue-2610](#2610)] +- Fixed VideoRoom recording not stopped for participants entering after global recording was started [[PR-2550](#2550)] +- Fixed 'audiocodec'/'videocodec' being ignored when joining a VideoRoom via 'joinandconfigure' +- Added content type support to MESSAGE in SIP plugin (thanks @tijmenNL!) [[PR-2567](#2567)] +- Made RTSP timeouts configurable in Streaming plugin (thanks @pontscho!) [[PR-2598](#2598)] +- Fixed incorrect parsing of backend URL in WebSockets event handler [[Issue-2603](#2603)] +- Added support for secure connections and lws debugging to WebSockets event handler +- Fixed occasionally broken AV1 recordings post-processing +- Other smaller fixes and improvements (thanks to all who contributed pull requests and reported issues!) + ## [v0.10.10] - 2021-02-06 - Reduced verbosity of a few LOG_WARN messages at startup From d52e33259de3088ff964440fafd17ca58f8ba9bc Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 6 Apr 2021 12:36:04 +0200 Subject: [PATCH 58/63] Fixed typo in CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19e574301d0..d99e9456a58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. -## [v0.11.0] - 2021-04-06 +## [v0.11.1] - 2021-04-06 - Add new option to configure ICE nomination mode, if libnice is recent enough [[PR-2541](#2541)] - Added support for per-session timeout values (thanks @alg!) [[PR-2577](#2577)] From 10ab360e7e3f93d317961e8f73b85814bfaa5b0b Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Tue, 6 Apr 2021 12:40:04 +0200 Subject: [PATCH 59/63] Bumbed to version 0.11.2 --- bower.json | 2 +- configure.ac | 6 +++--- docs/janus-doxygen.cfg | 2 +- janus.ggo | 2 +- postprocessing/janus-pp-rec.ggo | 2 +- postprocessing/pcap2mjr.ggo | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bower.json b/bower.json index a0d7c5acba0..ae4a7e12957 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "janus-gateway", - "version": "0.11.1", + "version": "0.11.2", "homepage": "https://github.com/meetecho/janus-gateway", "authors": [ "Lorenzo Miniero ", diff --git a/configure.ac b/configure.ac index 5bc18a71813..d6f1394c194 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([Janus WebRTC Server],[0.11.1],[https://github.com/meetecho/janus-gateway],[janus-gateway],[https://janus.conf.meetecho.com]) +AC_INIT([Janus WebRTC Server],[0.11.2],[https://github.com/meetecho/janus-gateway],[janus-gateway],[https://janus.conf.meetecho.com]) AC_LANG(C) AC_CONFIG_AUX_DIR([.]) AC_CONFIG_MACRO_DIR([m4]) @@ -75,9 +75,9 @@ cc*) -Wunused-but-set-variable" esac -JANUS_VERSION=111 +JANUS_VERSION=112 AC_SUBST(JANUS_VERSION) -JANUS_VERSION_STRING="0.11.1" +JANUS_VERSION_STRING="0.11.2" AC_SUBST(JANUS_VERSION_STRING) case "$host_os" in diff --git a/docs/janus-doxygen.cfg b/docs/janus-doxygen.cfg index 601adc97f2d..03c6f616f90 100644 --- a/docs/janus-doxygen.cfg +++ b/docs/janus-doxygen.cfg @@ -38,7 +38,7 @@ PROJECT_NAME = "Janus" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 0.11.1 +PROJECT_NUMBER = 0.11.2 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/janus.ggo b/janus.ggo index cc5b1318bb0..eff35103fa6 100644 --- a/janus.ggo +++ b/janus.ggo @@ -1,4 +1,4 @@ -#Janus 0.11.1 gengetopt file +#Janus 0.11.2 gengetopt file option "daemon" b "Launch Janus in background as a daemon" flag off option "pid-file" p "Open the specified PID file when starting Janus (default=none)" string typestr="path" optional option "disable-stdout" N "Disable stdout based logging" flag off diff --git a/postprocessing/janus-pp-rec.ggo b/postprocessing/janus-pp-rec.ggo index 4ebed2e3974..a240c7277a4 100644 --- a/postprocessing/janus-pp-rec.ggo +++ b/postprocessing/janus-pp-rec.ggo @@ -1,4 +1,4 @@ -#Janus-pp-rec 0.11.1 gengetopt file +#Janus-pp-rec 0.11.2 gengetopt file usage "janus-pp-rec [OPTIONS] source.mjr [destination.[opus|wav|webm|mp4|srt]]" option "json" j "Only print JSON header" flag off option "header" H "Only parse .mjr header" flag off diff --git a/postprocessing/pcap2mjr.ggo b/postprocessing/pcap2mjr.ggo index cb39039016e..039db8245dc 100644 --- a/postprocessing/pcap2mjr.ggo +++ b/postprocessing/pcap2mjr.ggo @@ -1,4 +1,4 @@ -#pcap2mjr 0.11.1 gengetopt file +#pcap2mjr 0.11.2 gengetopt file usage "pcap2mjr [OPTIONS] source.pcap destination.mjr" option "codec" c "Codec the recording will contain (e.g., opus, vp8, etc.)" string typestr="codec" required option "ssrc" s "SSRC of the packets in the pcap file to save" int typestr="ssrc" required From 6f14b5d8890a74b8c6495fc878ad36e9be70b293 Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Wed, 7 Apr 2021 12:09:13 +0200 Subject: [PATCH 60/63] Added missing mutex initialization (fixes #2622) --- plugins/janus_streaming.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/janus_streaming.c b/plugins/janus_streaming.c index 6a04b818db9..07b8b3ce444 100644 --- a/plugins/janus_streaming.c +++ b/plugins/janus_streaming.c @@ -1159,7 +1159,7 @@ typedef struct janus_streaming_mountpoint { janus_refcount ref; } janus_streaming_mountpoint; GHashTable *mountpoints = NULL, *mountpoints_temp = NULL; -janus_mutex mountpoints_mutex; +janus_mutex mountpoints_mutex = JANUS_MUTEX_INITIALIZER; static char *admin_key = NULL; typedef struct janus_streaming_helper { From f79b41cf53aa61c389e9aca026132fec278af2e3 Mon Sep 17 00:00:00 2001 From: Imer Husejnovic Date: Wed, 7 Apr 2021 12:13:23 +0200 Subject: [PATCH 61/63] SIP plugin: SIP MESSAGE out of dialog (#2616) --- plugins/janus_sip.c | 107 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 24 deletions(-) diff --git a/plugins/janus_sip.c b/plugins/janus_sip.c index 84d79937003..e4bf007ff72 100644 --- a/plugins/janus_sip.c +++ b/plugins/janus_sip.c @@ -406,13 +406,17 @@ * and will restore the media direction that was set in the SDP before * putting the call on-hold. * - * The \c message request allows you to send a SIP MESSAGE to the peer: + * The \c message request allows you to send a SIP MESSAGE to the peer. + * By default, it is sent in dialog, during active call. + * But, if the user is registered, it might be sent out of dialog also. In that case the uri parameter is required. * \verbatim { "request" : "message", "content_type" : "" - "content" : "" + "content" : "", + "uri" : "", + "headers" : "" } \endverbatim * @@ -801,7 +805,9 @@ static struct janus_json_parameter info_parameters[] = { }; static struct janus_json_parameter sipmessage_parameters[] = { {"content_type", JSON_STRING, 0}, - {"content", JSON_STRING, JANUS_JSON_PARAM_REQUIRED} + {"content", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}, + {"uri", JSON_STRING, 0}, + {"headers", JSON_OBJECT, 0} }; /* Useful stuff */ @@ -910,7 +916,7 @@ struct ssip_s { su_home_t s_home[1]; su_root_t *s_root; nua_t *s_nua; - nua_handle_t *s_nh_r, *s_nh_i; + nua_handle_t *s_nh_r, *s_nh_i, *s_nh_m; GHashTable *subscriptions; janus_mutex smutex; struct janus_sip_session *session; @@ -4467,28 +4473,49 @@ static void *janus_sip_handler(void *data) { json_object_set_new(result, "event", json_string("infosent")); } else if(!strcasecmp(request_text, "message")) { /* Send a SIP MESSAGE request: we'll only need the content and optional payload type */ - if(!(session->status == janus_sip_call_status_inviting || - janus_sip_call_is_established(session))) { - JANUS_LOG(LOG_ERR, "Wrong state (not established? status=%s)\n", janus_sip_call_status_string(session->status)); - g_snprintf(error_cause, 512, "Wrong state (not in a call?)"); - goto error; - } - janus_mutex_lock(&session->mutex); - if(session->callee == NULL) { - janus_mutex_unlock(&session->mutex); - JANUS_LOG(LOG_ERR, "Wrong state (no callee?)\n"); - error_code = JANUS_SIP_ERROR_WRONG_STATE; - g_snprintf(error_cause, 512, "Wrong state (no callee?)"); - goto error; - } - janus_mutex_unlock(&session->mutex); JANUS_VALIDATE_JSON_OBJECT(root, sipmessage_parameters, error_code, error_cause, TRUE, JANUS_SIP_ERROR_MISSING_ELEMENT, JANUS_SIP_ERROR_INVALID_ELEMENT); if(error_code != 0) { - janus_mutex_unlock(&session->mutex); goto error; } + gboolean in_dialog_message = TRUE; + json_t *uri = json_object_get(root, "uri"); + const char *uri_text = json_string_value(uri); + if(uri != NULL) + in_dialog_message = FALSE; + + if(in_dialog_message) { + if(!(session->status == janus_sip_call_status_inviting || janus_sip_call_is_established(session))) { + JANUS_LOG(LOG_ERR, "Wrong state (not established? status=%s)\n", janus_sip_call_status_string(session->status)); + g_snprintf(error_cause, 512, "Wrong state (not in a call?)"); + goto error; + } + janus_mutex_lock(&session->mutex); + if(session->callee == NULL) { + janus_mutex_unlock(&session->mutex); + JANUS_LOG(LOG_ERR, "Wrong state (no callee?)\n"); + error_code = JANUS_SIP_ERROR_WRONG_STATE; + g_snprintf(error_cause, 512, "Wrong state (no callee?)"); + goto error; + } + janus_mutex_unlock(&session->mutex); + } else { + if(session->account.registration_status != janus_sip_registration_status_registered && + session->account.registration_status != janus_sip_registration_status_disabled) { + JANUS_LOG(LOG_ERR, "Wrong state (not registered)\n"); + error_code = JANUS_SIP_ERROR_WRONG_STATE; + g_snprintf(error_cause, 512, "Wrong state (not registered)"); + goto error; + } + janus_sip_uri_t target_uri; + if(janus_sip_parse_uri(&target_uri, uri_text) < 0) { + JANUS_LOG(LOG_ERR, "Invalid user address %s\n", uri_text); + error_code = JANUS_SIP_ERROR_INVALID_ADDRESS; + g_snprintf(error_cause, 512, "Invalid user address %s\n", uri_text); + goto error; + } + } const char *content_type = "text/plain"; json_t *content_type_text = json_object_get(root, "content_type"); @@ -4496,10 +4523,37 @@ static void *janus_sip_handler(void *data) { content_type = json_string_value(content_type_text); const char *msg_content = json_string_value(json_object_get(root, "content")); - nua_message(session->stack->s_nh_i, - SIPTAG_CONTENT_TYPE_STR(content_type), - SIPTAG_PAYLOAD_STR(msg_content), - TAG_END()); + char custom_headers[2048]; + janus_sip_parse_custom_headers(root, (char *)&custom_headers, sizeof(custom_headers)); + + if(in_dialog_message) { + nua_message(session->stack->s_nh_i, + SIPTAG_CONTENT_TYPE_STR(content_type), + SIPTAG_PAYLOAD_STR(msg_content), + TAG_IF(strlen(custom_headers) > 0, SIPTAG_HEADER_STR(custom_headers)), + TAG_END()); + } else { + janus_mutex_lock(&session->stack->smutex); + if(session->stack->s_nh_m == NULL) { + if (session->stack->s_nua == NULL) { + janus_mutex_unlock(&session->stack->smutex); + JANUS_LOG(LOG_ERR, "NUA destroyed while sending message?\n"); + error_code = JANUS_SIP_ERROR_LIBSOFIA_ERROR; + g_snprintf(error_cause, 512, "Invalid NUA"); + goto error; + } + session->stack->s_nh_m = nua_handle(session->stack->s_nua, session, TAG_END()); + } + janus_mutex_unlock(&session->stack->smutex); + nua_message(session->stack->s_nh_m, + SIPTAG_TO_STR(uri_text), + SIPTAG_CONTENT_TYPE_STR(content_type), + SIPTAG_PAYLOAD_STR(msg_content), + NUTAG_PROXY(session->helper && session->master ? + session->master->account.outbound_proxy : session->account.outbound_proxy), + TAG_IF(strlen(custom_headers) > 0, SIPTAG_HEADER_STR(custom_headers)), + TAG_END()); + } /* Notify the operation */ result = json_object(); json_object_set_new(result, "event", json_string("messagesent")); @@ -6649,6 +6703,7 @@ gpointer janus_sip_sofia_thread(gpointer user_data) { session->stack->s_nua = NULL; session->stack->s_nh_r = NULL; session->stack->s_nh_i = NULL; + session->stack->s_nh_m = NULL; session->stack->s_root = su_root_create(session->stack); session->stack->subscriptions = NULL; janus_mutex_init(&session->stack->smutex); @@ -6698,6 +6753,10 @@ gpointer janus_sip_sofia_thread(gpointer user_data) { nua_handle_destroy(session->stack->s_nh_i); session->stack->s_nh_i = NULL; } + if(session->stack->s_nh_m != NULL) { + nua_handle_destroy(session->stack->s_nh_m); + session->stack->s_nh_m = NULL; + } nua_destroy(s_nua); su_root_destroy(session->stack->s_root); session->stack->s_root = NULL; From 702af25139e1dca2547d76a947835d3fbc046378 Mon Sep 17 00:00:00 2001 From: Sergey Radionov Date: Wed, 7 Apr 2021 22:15:37 +0700 Subject: [PATCH 62/63] mqttevh: added ability use relative to config paths in config (#2623) --- events/janus_mqttevh.c | 6 +++--- utils.c | 10 ++++++++++ utils.h | 7 +++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/events/janus_mqttevh.c b/events/janus_mqttevh.c index 7be87a6eb71..14327f42f62 100644 --- a/events/janus_mqttevh.c +++ b/events/janus_mqttevh.c @@ -929,7 +929,7 @@ static int janus_mqttevh_init(const char *config_path) { item = janus_config_get(config, config_general, janus_config_type_item, "ssl_cacert"); } if(item && item->value) { - ctx->tls.cacert_file = g_strdup(item->value); + ctx->tls.cacert_file = janus_make_absolute_path(config_path, item->value); } item = janus_config_get(config, config_general, janus_config_type_item, "tls_client_cert"); @@ -937,14 +937,14 @@ static int janus_mqttevh_init(const char *config_path) { item = janus_config_get(config, config_general, janus_config_type_item, "ssl_client_cert"); } if(item && item->value) { - ctx->tls.cert_file = g_strdup(item->value); + ctx->tls.cert_file = janus_make_absolute_path(config_path, item->value); } item = janus_config_get(config, config_general, janus_config_type_item, "tls_client_key"); if(!item) { item = janus_config_get(config, config_general, janus_config_type_item, "ssl_client_key"); } if(item && item->value) { - ctx->tls.key_file = g_strdup(item->value); + ctx->tls.key_file = janus_make_absolute_path(config_path, item->value); } item = janus_config_get(config, config_general, janus_config_type_item, "tls_verify_peer"); if(!item) { diff --git a/utils.c b/utils.c index c06f0c23aaf..ca3f46004d7 100644 --- a/utils.c +++ b/utils.c @@ -296,6 +296,16 @@ int janus_mkdir(const char *dir, mode_t mode) { return 0; } +gchar *janus_make_absolute_path(const gchar *base_dir, const gchar *path) { + if(!path) + return NULL; + if(g_path_is_absolute(path)) + return g_strdup(path); + if(!base_dir) + return NULL; + return g_build_filename(base_dir, path, NULL); +} + int janus_get_codec_pt(const char *sdp, const char *codec) { if(!sdp || !codec) return -1; diff --git a/utils.h b/utils.h index 5388aedb2a2..127433e793c 100644 --- a/utils.h +++ b/utils.h @@ -143,6 +143,13 @@ gboolean janus_flags_is_set(janus_flags *flags, gsize flag); * @note A failure may indicate that creating any of the subdirectories failed: some may still have been created */ int janus_mkdir(const char *dir, mode_t mode); +/*! \brief Helper to convert \c path relative to \c base_dir to absolute path. + * If \c path already represents absolute path then just g_strdup it. + * @param[in] base_dir Path which will be prepended to \c path if it's relative + * @param[in] path Some relative or absolute path + * @returns g_strdup'ed absolute path. Should be freed with g_free() when no longer needed */ +gchar *janus_make_absolute_path(const gchar *base_dir, const gchar *path); + /*! \brief Ugly and dirty helper to quickly get the payload type associated with a codec in an SDP * @param sdp The SDP to parse * @param codec The codec to look for From e674f1a808dbd75b762f79de1e1f11080d12e2fd Mon Sep 17 00:00:00 2001 From: Lorenzo Miniero Date: Wed, 7 Apr 2021 18:10:37 +0200 Subject: [PATCH 63/63] Add info on moderation to list of publishers, if enabled --- plugins/janus_videoroom.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index 1d72f82f1db..c1f7266e715 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -480,6 +480,9 @@ room-: { "display" : "", "audio_codec" : "