Skip to content

Commit

Permalink
Spatial audio support in AudioBridge via stereo mixing (meetecho#2446)
Browse files Browse the repository at this point in the history
  • Loading branch information
lminiero committed May 27, 2021
1 parent 161fe7a commit 5757a37
Show file tree
Hide file tree
Showing 4 changed files with 264 additions and 59 deletions.
1 change: 1 addition & 0 deletions conf/janus.plugin.audiobridge.jcfg.sample
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# secret = "<optional password needed for manipulating (e.g. destroying) the room>"
# pin = "<optional password needed for joining the room>"
# sampling_rate = <sampling rate> (e.g., 16000 for wideband mixing)
# spatial_audio = true|false (if true, the mix will be stereo to spatially place users, default=false)
# audiolevel_ext = true|false (whether the ssrc-audio-level RTP extension must
# be negotiated/used or not for new joins, default=true)
# audiolevel_event = true|false (whether to emit event to other users or not, default=false)
Expand Down
5 changes: 4 additions & 1 deletion html/audiobridgetest.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/5.4.0/bootbox.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/spin.js/2.3.2/spin.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/10.6.2/bootstrap-slider.min.js"></script>
<script type="text/javascript" src="janus.js" ></script>
<script type="text/javascript" src="audiobridgetest.js"></script>
<script>
Expand All @@ -25,6 +26,7 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootswatch/3.4.0/cerulean/bootstrap.min.css" type="text/css"/>
<link rel="stylesheet" href="css/demo.css" type="text/css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" type="text/css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/10.6.2/css/bootstrap-slider.css" type="text/css"/>
</head>
<body>

Expand Down Expand Up @@ -80,7 +82,8 @@ <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></h3>
<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>
<div class="panel-body">
<ul id="list" class="list-group">
Expand Down
102 changes: 79 additions & 23 deletions html/audiobridgetest.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ var spinner = null;
var myroom = 1234; // Demo room
if(getQueryStringValue("room") !== "")
myroom = parseInt(getQueryStringValue("room"));
var stereo = false;
if(getQueryStringValue("stereo") !== "")
stereo = (getQueryStringValue("stereo") === "true");
var myusername = null;
var myid = null;
var webrtcUp = false;
Expand Down Expand Up @@ -146,7 +149,13 @@ $(document).ready(function() {
// Publish our stream
mixertest.createOffer(
{
media: { video: false}, // This is an audio only room
media: { video: false }, // This is an audio only room
customizeSdp: function(jsep) {
if(stereo && jsep.sdp.indexOf("stereo=1") == -1) {
// Make sure that our offer contains stereo too
jsep.sdp = jsep.sdp.replace("useinbandfec=1", "useinbandfec=1;stereo=1");
}
},
success: function(jsep) {
Janus.debug("Got SDP!", jsep);
var publish = { request: "configure", muted: false };
Expand All @@ -168,22 +177,34 @@ $(document).ready(function() {
var display = list[f]["display"];
var setup = list[f]["setup"];
var muted = list[f]["muted"];
var spatial = list[f]["spatial_position"];
Janus.debug(" >> [" + id + "] " + display + " (setup=" + setup + ", muted=" + muted + ")");
if($('#rp'+id).length === 0) {
if($('#rp' + id).length === 0) {
// Add to the participants list
$('#list').append('<li id="rp'+id+'" class="list-group-item">'+display+
var slider = '';
if(spatial !== null && spatial !== undefined)
slider = '<span>[L <input id="sp' + id + '" type="text" style="width: 10%;"/> R] </span>';
$('#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>');
$('#rp'+id + ' > i').hide();
if(spatial !== null && spatial !== undefined) {
$('#sp' + id).slider({ min: 0, max: 100, step: 1, value: 50, handle: 'triangle', enabled: false });
$('#position').removeClass('hide').show();
}
$('#rp' + id + ' > i').hide();
}
if(muted === true || muted === "true")
$('#rp'+id + ' > i.abmuted').removeClass('hide').show();
$('#rp' + id + ' > i.abmuted').removeClass('hide').show();
else
$('#rp'+id + ' > i.abmuted').hide();
$('#rp' + id + ' > i.abmuted').hide();
if(setup === true || setup === "true")
$('#rp'+id + ' > i.absetup').hide();
$('#rp' + id + ' > i.absetup').hide();
else
$('#rp'+id + ' > i.absetup').removeClass('hide').show();
$('#rp' + id + ' > i.absetup').removeClass('hide').show();
if(spatial !== null && spatial !== undefined)
$('#sp' + id).slider('setValue', spatial);
}
}
} else if(event === "roomchanged") {
Expand All @@ -200,22 +221,34 @@ $(document).ready(function() {
var display = list[f]["display"];
var setup = list[f]["setup"];
var muted = list[f]["muted"];
var spatial = list[f]["spatial_position"];
Janus.debug(" >> [" + id + "] " + display + " (setup=" + setup + ", muted=" + muted + ")");
if($('#rp'+id).length === 0) {
if($('#rp' + id).length === 0) {
// Add to the participants list
$('#list').append('<li id="rp'+id+'" class="list-group-item">'+display+
var slider = '';
if(spatial !== null && spatial !== undefined)
slider = '<span>[L <input id="sp' + id + '" type="text" style="width: 10%;"/> R] </span>';
$('#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>');
$('#rp'+id + ' > i').hide();
if(spatial !== null && spatial !== undefined) {
$('#sp' + id).slider({ min: 0, max: 100, step: 1, value: 50, handle: 'triangle', enabled: false });
$('#position').removeClass('hide').show();
}
$('#rp' + id + ' > i').hide();
}
if(muted === true || muted === "true")
$('#rp'+id + ' > i.abmuted').removeClass('hide').show();
$('#rp' + id + ' > i.abmuted').removeClass('hide').show();
else
$('#rp'+id + ' > i.abmuted').hide();
$('#rp' + id + ' > i.abmuted').hide();
if(setup === true || setup === "true")
$('#rp'+id + ' > i.absetup').hide();
$('#rp' + id + ' > i.absetup').hide();
else
$('#rp'+id + ' > i.absetup').removeClass('hide').show();
$('#rp' + id + ' > i.absetup').removeClass('hide').show();
if(spatial !== null && spatial !== undefined)
$('#sp' + id).slider('setValue', spatial);
}
}
} else if(event === "destroyed") {
Expand All @@ -233,22 +266,34 @@ $(document).ready(function() {
var display = list[f]["display"];
var setup = list[f]["setup"];
var muted = list[f]["muted"];
var spatial = list[f]["spatial_position"];
Janus.debug(" >> [" + id + "] " + display + " (setup=" + setup + ", muted=" + muted + ")");
if($('#rp'+id).length === 0) {
if($('#rp' + id).length === 0) {
// Add to the participants list
$('#list').append('<li id="rp'+id+'" class="list-group-item">'+display+
var slider = '';
if(spatial !== null && spatial !== undefined)
slider = '<span>[L <input id="sp' + id + '" type="text" style="width: 10%;"/> R] </span>';
$('#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>');
$('#rp'+id + ' > i').hide();
if(spatial !== null && spatial !== undefined) {
$('#sp' + id).slider({ min: 0, max: 100, step: 1, value: 50, handle: 'triangle', enabled: false });
$('#position').removeClass('hide').show();
}
$('#rp' + id + ' > i').hide();
}
if(muted === true || muted === "true")
$('#rp'+id + ' > i.abmuted').removeClass('hide').show();
$('#rp' + id + ' > i.abmuted').removeClass('hide').show();
else
$('#rp'+id + ' > i.abmuted').hide();
$('#rp' + id + ' > i.abmuted').hide();
if(setup === true || setup === "true")
$('#rp'+id + ' > i.absetup').hide();
$('#rp' + id + ' > i.absetup').hide();
else
$('#rp'+id + ' > i.absetup').removeClass('hide').show();
$('#rp' + id + ' > i.absetup').removeClass('hide').show();
if(spatial !== null && spatial !== undefined)
$('#sp' + id).slider('setValue', spatial);
}
} else if(msg["error"]) {
if(msg["error_code"] === 485) {
Expand Down Expand Up @@ -306,7 +351,18 @@ $(document).ready(function() {
$('#toggleaudio').html("Unmute").removeClass("btn-danger").addClass("btn-success");
mixertest.send({ message: { request: "configure", muted: !audioenabled }});
}).removeClass('hide').show();

// Spatial position, if enabled
$('#position').click(
function() {
bootbox.prompt("Insert new spatial position: [0-100] (0=left, 50=center, 100=right)", function(result) {
var spatial = parseInt(result);
if(isNaN(spatial) || spatial < 0 || spatial > 100) {
bootbox.alert("Invalid value");
return;
}
mixertest.send({ message: { request: "configure", spatial_position: spatial }});
});
});
},
oncleanup: function() {
webrtcUp = false;
Expand Down
Loading

0 comments on commit 5757a37

Please sign in to comment.