Skip to content

Commit

Permalink
Added suspend/resume participant API to AudioBridge (1.x) (#3301)
Browse files Browse the repository at this point in the history
  • Loading branch information
lminiero authored Dec 5, 2023
1 parent ad0d640 commit a85a734
Show file tree
Hide file tree
Showing 7 changed files with 604 additions and 116 deletions.
8 changes: 8 additions & 0 deletions conf/janus.jcfg.sample.in
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,14 @@ nat: {
#ice_lite = true
#ice_tcp = true

# By default, Janus implements a grace period when detecting ICE
# failures in PeerConnections, to give time to applications to react
# to that, e.g., by enforcing an ICE restart. If you want an ICE
# failure to result in the PeerConnection being closed right away
# (e.g., with the help of consent freshness) then you can do that
# by uncommenting the following property and set it to true
#hangup_on_failed = true

# By default Janus tries to resolve mDNS (.local) candidates: even
# though this is now done asynchronously and shouldn't keep the API
# busy, even in case mDNS resolution takes a long time to timeout,
Expand Down
8 changes: 6 additions & 2 deletions html/audiobridgetest.html
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,12 @@ <h3>Demo details</h3>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Participants <span class="label label-info hide" id="participant"></span>
<button class="btn-xs btn-danger hide pull-right" autocomplete="off" id="toggleaudio">Mute</button>
<button class="btn-xs btn-primary hide pull-right" autocomplete="off" id="position">Position</button></h3>
<div class="btn-group btn-group-xs pull-right">
<button class="btn btn-primary hide" autocomplete="off" id="position">Position</button>
<button class="btn btn-danger hide" autocomplete="off" id="toggleaudio">Mute</button>
<button class="btn btn-danger hide" autocomplete="off" id="togglesuspend">Suspend</button>
</div>
</h3>
</div>
<div class="panel-body">
<ul id="list" class="list-group">
Expand Down
57 changes: 50 additions & 7 deletions html/audiobridgetest.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ if(getQueryStringValue("group") !== "")
var myusername = null;
var myid = null;
var webrtcUp = false;
var audioenabled = false;
var audioenabled = false, audiosuspended = false;


$(document).ready(function() {
Expand Down Expand Up @@ -146,6 +146,7 @@ $(document).ready(function() {
let display = escapeXmlTags(list[f]["display"]);
let setup = list[f]["setup"];
let muted = list[f]["muted"];
let suspended = list[f]["suspended"];
let spatial = list[f]["spatial_position"];
Janus.debug(" >> [" + id + "] " + display + " (setup=" + setup + ", muted=" + muted + ")");
if($('#rp' + id).length === 0) {
Expand All @@ -156,8 +157,9 @@ $(document).ready(function() {
$('#list').append('<li id="rp' + id +'" class="list-group-item">' +
slider +
display +
' <i class="absetup fa fa-chain-broken"></i>' +
' <i class="abmuted fa fa-microphone-slash"></i></li>');
' <i class="absetup fa fa-chain-broken" title="No PeerConnection"></i>' +
' <i class="absusp fa fa-eye-slash" title="Suspended"></i>' +
' <i class="abmuted fa fa-microphone-slash" title="Muted"></i></li>');
if(spatial !== null && spatial !== undefined) {
$('#sp' + id).slider({ min: 0, max: 100, step: 1, value: 50, handle: 'triangle', enabled: false });
$('#position').removeClass('hide').show();
Expand All @@ -172,6 +174,10 @@ $(document).ready(function() {
$('#rp' + id + ' > i.absetup').hide();
else
$('#rp' + id + ' > i.absetup').removeClass('hide').show();
if(suspended === true)
$('#rp' + id + ' > i.absusp').removeClass('hide').show();
else
$('#rp' + id + ' > i.absusp').hide();
if(spatial !== null && spatial !== undefined)
$('#sp' + id).slider('setValue', spatial);
}
Expand All @@ -190,6 +196,7 @@ $(document).ready(function() {
let display = escapeXmlTags(list[f]["display"]);
let setup = list[f]["setup"];
let muted = list[f]["muted"];
let suspended = list[f]["suspended"];
let spatial = list[f]["spatial_position"];
Janus.debug(" >> [" + id + "] " + display + " (setup=" + setup + ", muted=" + muted + ")");
if($('#rp' + id).length === 0) {
Expand All @@ -200,8 +207,9 @@ $(document).ready(function() {
$('#list').append('<li id="rp' + id +'" class="list-group-item">' +
slider +
display +
' <i class="absetup fa fa-chain-broken"></i>' +
' <i class="abmuted fa fa-microphone-slash"></i></li>');
' <i class="absetup fa fa-chain-broken" title="No PeerConnection"></i>' +
' <i class="absusp fa fa-eye-slash" title="Suspended"></i>' +
' <i class="abmuted fa fa-microphone-slash" title="Muted"></i></li>');
if(spatial !== null && spatial !== undefined) {
$('#sp' + id).slider({ min: 0, max: 100, step: 1, value: 50, handle: 'triangle', enabled: false });
$('#position').removeClass('hide').show();
Expand All @@ -216,6 +224,10 @@ $(document).ready(function() {
$('#rp' + id + ' > i.absetup').hide();
else
$('#rp' + id + ' > i.absetup').removeClass('hide').show();
if(suspended === true)
$('#rp' + id + ' > i.absusp').removeClass('hide').show();
else
$('#rp' + id + ' > i.absusp').hide();
if(spatial !== null && spatial !== undefined)
$('#sp' + id).slider('setValue', spatial);
}
Expand All @@ -228,13 +240,18 @@ $(document).ready(function() {
});
} else if(event === "event") {
if(msg["participants"]) {
if(msg["resumed"]) {
// This is a full recap after a suspend: clear the list of participants
$('#list').empty();
}
let list = msg["participants"];
Janus.debug("Got a list of participants:", list);
for(let f in list) {
let id = list[f]["id"];
let display = escapeXmlTags(list[f]["display"]);
let setup = list[f]["setup"];
let muted = list[f]["muted"];
let suspended = list[f]["suspended"];
let spatial = list[f]["spatial_position"];
Janus.debug(" >> [" + id + "] " + display + " (setup=" + setup + ", muted=" + muted + ")");
if($('#rp' + id).length === 0) {
Expand All @@ -245,8 +262,9 @@ $(document).ready(function() {
$('#list').append('<li id="rp' + id +'" class="list-group-item">' +
slider +
display +
' <i class="absetup fa fa-chain-broken"></i>' +
' <i class="abmuted fa fa-microphone-slash"></i></li>');
' <i class="absetup fa fa-chain-broken" title="No PeerConnection"></i>' +
' <i class="absusp fa fa-eye-slash" title="Suspended"></i>' +
' <i class="abmuted fa fa-microphone-slash" title="Muted"></i></li>');
if(spatial !== null && spatial !== undefined) {
$('#sp' + id).slider({ min: 0, max: 100, step: 1, value: 50, handle: 'triangle', enabled: false });
$('#position').removeClass('hide').show();
Expand All @@ -261,9 +279,19 @@ $(document).ready(function() {
$('#rp' + id + ' > i.absetup').hide();
else
$('#rp' + id + ' > i.absetup').removeClass('hide').show();
if(suspended === true)
$('#rp' + id + ' > i.absusp').removeClass('hide').show();
else
$('#rp' + id + ' > i.absusp').hide();
if(spatial !== null && spatial !== undefined)
$('#sp' + id).slider('setValue', spatial);
}
} else if(msg["suspended"]) {
let id = msg["suspended"];
$('#rp' + id + ' > i.absusp').removeClass('hide').show();
} else if(msg["resumed"]) {
let id = msg["resumed"];
$('#rp' + id + ' > i.absusp').hide();
} else if(msg["error"]) {
if(msg["error_code"] === 485) {
// This is a "no such room" error: give a more meaningful description
Expand Down Expand Up @@ -330,6 +358,21 @@ $(document).ready(function() {
$('#toggleaudio').html("Unmute").removeClass("btn-danger").addClass("btn-success");
mixertest.send({ message: { request: "configure", muted: !audioenabled }});
}).removeClass('hide').show();
// Suspend button
audiosuspended = false;
$('#togglesuspend').click(
function() {
audiosuspended = !audiosuspended;
if(!audiosuspended)
$('#togglesuspend').html("Suspend").removeClass("btn-success").addClass("btn-danger");
else
$('#togglesuspend').html("Resume").removeClass("btn-danger").addClass("btn-success");
mixertest.send({ message: {
request: (audiosuspended ? "suspend" : "resume"),
room: myroom,
id: myid
}});
}).removeClass('hide').show();
// Spatial position, if enabled
$('#position').click(
function() {
Expand Down
22 changes: 21 additions & 1 deletion src/ice.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,18 @@ gboolean janus_ice_is_keepalive_conncheck_enabled(void) {
return janus_ice_keepalive_connchecks;
}

/* How to react to ICE failures */
static gboolean janus_ice_hangup_on_failed = FALSE;
void janus_ice_set_hangup_on_failed_enabled(gboolean enabled) {
janus_ice_hangup_on_failed = enabled;
if(janus_ice_hangup_on_failed) {
JANUS_LOG(LOG_INFO, "Will hangup PeerConnections immediately on ICE failures\n");
}
}
gboolean janus_ice_is_hangup_on_failed_enabled(void) {
return janus_ice_hangup_on_failed;
}

/* 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 */
Expand Down Expand Up @@ -2143,7 +2155,15 @@ static void janus_ice_cb_component_state_changed(NiceAgent *agent, guint stream_
if(prev_state == NICE_COMPONENT_STATE_CONNECTED || prev_state == NICE_COMPONENT_STATE_READY) {
/* Failed after connected/ready means consent freshness detected something broken:
* notify the user via a Janus API event and then fire the 'failed' timer as sual */
janus_ice_notify_ice_failed(handle);
janus_ice_notify_ice_failed(handle);
/* Check if we need to hangup right away, rather than start the grace period */
if(janus_ice_hangup_on_failed && pc->icefailed_detected == 0) {
/* We do, hangup the PeerConnection */
JANUS_LOG(LOG_ERR, "[%"SCNu64"] ICE failed for component %d in stream %d...\n",
handle->handle_id, component_id, stream_id);
janus_ice_webrtc_hangup(handle, "ICE failed");
return;
}
}
gboolean trickle_recv = (!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_TRICKLE) || janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES));
gboolean answer_recv = janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_GOT_ANSWER);
Expand Down
6 changes: 6 additions & 0 deletions src/ice.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,12 @@ 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 enable/disable immediate hangups of PeerConnectionss on ICE failures.
* @param[in] enabled Whether the functionality should be enabled or disabled */
void janus_ice_set_hangup_on_failed_enabled(gboolean enabled);
/*! \brief Method to check whether ICE failures will result in immediate hangups
* @returns true if enabled, false (default) otherwise */
gboolean janus_ice_is_hangup_on_failed_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);
Expand Down
4 changes: 4 additions & 0 deletions src/janus.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ static json_t *janus_info(const char *transaction) {
#endif
json_object_set_new(info, "ice-consent-freshness", janus_ice_is_consent_freshness_enabled() ? json_true() : json_false());
json_object_set_new(info, "ice-keepalive-conncheck", janus_ice_is_keepalive_conncheck_enabled() ? json_true() : json_false());
json_object_set_new(info, "hangup-on-failed", janus_ice_is_hangup_on_failed_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()));
Expand Down Expand Up @@ -5230,6 +5231,9 @@ gint main(int argc, char *argv[]) {
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));
item = janus_config_get(config, config_nat, janus_config_type_item, "hangup_on_failed");
if(item && item->value)
janus_ice_set_hangup_on_failed_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);
Expand Down
Loading

0 comments on commit a85a734

Please sign in to comment.