Simulcast.

This commit is contained in:
Juliusz Chroboczek
2021-05-08 21:12:29 +02:00
parent f1a15f07db
commit 795a40ceaf
11 changed files with 218 additions and 112 deletions
+2
View File
@@ -213,7 +213,9 @@
<select id="requestselect" class="select select-inline">
<option value="">nothing</option>
<option value="audio">audio only</option>
<option value="screenshare-low">screen share (low)</option>
<option value="screenshare">screen share</option>
<option value="everything-low">everything (low)</option>
<option value="everything" selected>everything</option>
</select>
</form>
+60 -24
View File
@@ -78,6 +78,7 @@ function getUserPass() {
* @property {boolean} [localMute]
* @property {string} [video]
* @property {string} [audio]
* @property {boolean} [simulcast]
* @property {string} [send]
* @property {string} [request]
* @property {boolean} [activityDetection]
@@ -550,9 +551,15 @@ function mapRequest(what) {
case 'audio':
return {'': ['audio']};
break;
case 'screenshare-low':
return {screenshare: ['audio','video-low'], '': ['audio']};
break;
case 'screenshare':
return {screenshare: ['audio','video'], '': ['audio']};
break;
case 'everything-low':
return {'': ['audio','video-low']};
break;
case 'everything':
return {'': ['audio','video']}
break;
@@ -611,20 +618,25 @@ getInputElement('fileinput').onchange = function(e) {
function gotUpStats(stats) {
let c = this;
let text = '';
let values = [];
c.pc.getSenders().forEach(s => {
let tid = s.track && s.track.id;
let stats = tid && c.stats[tid];
let rate = stats && stats['outbound-rtp'] && stats['outbound-rtp'].rate;
if(typeof rate === 'number') {
if(text)
text = text + ' + ';
text = text + Math.round(rate / 1000) + 'kbps';
for(let id in stats) {
if(stats[id] && stats[id]['outbound-rtp']) {
let rate = stats[id]['outbound-rtp'].rate;
if(typeof rate === 'number') {
values.push(rate);
}
}
});
}
setLabel(c, text);
if(values.length === 0) {
setLabel(c, '');
} else {
values.sort((x,y) => x - y);
setLabel(c, values
.map(x => Math.round(x / 1000).toString())
.reduce((x, y) => x + '+' + y));
}
}
/**
@@ -800,6 +812,7 @@ function newUpStream(localId) {
* @param {number} [bps]
*/
async function setMaxVideoThroughput(c, bps) {
let simulcast = doSimulcast();
let senders = c.pc.getSenders();
for(let i = 0; i < senders.length; i++) {
let s = senders[i];
@@ -808,17 +821,17 @@ async function setMaxVideoThroughput(c, bps) {
let p = s.getParameters();
if(!p.encodings)
p.encodings = [{}];
p.encodings.forEach(e => {
if(bps > 0)
e.maxBitrate = bps;
else
delete e.maxBitrate;
});
try {
await s.setParameters(p);
} catch(e) {
console.error(e);
if((!simulcast && p.encodings.length != 1) ||
(simulcast && p.encodings.length != 2)) {
// change the simulcast envelope
await replaceUpStream(c);
return;
}
p.encodings.forEach(e => {
if(!e.rid || e.rid === 'h')
e.maxBitrate = bps || unlimitedRate;
});
await s.setParameters(p);
}
}
@@ -1022,6 +1035,19 @@ function isSafari() {
return ua.indexOf('safari') >= 0 && ua.indexOf('chrome') < 0;
}
const unlimitedRate = 1000000000;
const simulcastRate = 100000;
/**
* @returns {boolean}
*/
function doSimulcast() {
if(!getSettings().simulcast)
return false;
let bps = getMaxVideoThroughput();
return bps <= 0 || bps >= 2 * simulcastRate;
}
/**
* Sets up c to send the given stream. Some extra parameters are stored
* in c.userdata.
@@ -1029,6 +1055,7 @@ function isSafari() {
* @param {Stream} c
* @param {MediaStream} stream
*/
function setUpStream(c, stream) {
if(c.stream != null)
throw new Error("Setting nonempty stream");
@@ -1073,11 +1100,20 @@ function setUpStream(c, stream) {
c.close();
};
let encodings = [{}];
let encodings = [];
if(t.kind === 'video') {
let simulcast = doSimulcast();
let bps = getMaxVideoThroughput();
if(bps > 0)
encodings[0].maxBitrate = bps;
encodings.push({
rid: 'h',
maxBitrate: bps || unlimitedRate,
});
if(simulcast)
encodings.push({
rid: 'l',
scaleResolutionDownBy: 2,
maxBitrate: simulcastRate,
});
}
c.pc.addTransceiver(t, {
direction: 'sendonly',
+12 -9
View File
@@ -1246,17 +1246,20 @@ Stream.prototype.updateStats = async function() {
if(report) {
for(let r of report.values()) {
if(stid && r.type === 'outbound-rtp') {
let id = stid;
if(r.rid)
id = id + '-' + r.rid
if(!('bytesSent' in r))
continue;
if(!stats[stid])
stats[stid] = {};
stats[stid][r.type] = {};
stats[stid][r.type].timestamp = r.timestamp;
stats[stid][r.type].bytesSent = r.bytesSent;
if(old[stid] && old[stid][r.type])
stats[stid][r.type].rate =
((r.bytesSent - old[stid][r.type].bytesSent) * 1000 /
(r.timestamp - old[stid][r.type].timestamp)) * 8;
if(!stats[id])
stats[id] = {};
stats[id][r.type] = {};
stats[id][r.type].timestamp = r.timestamp;
stats[id][r.type].bytesSent = r.bytesSent;
if(old[id] && old[id][r.type])
stats[id][r.type].rate =
((r.bytesSent - old[id][r.type].bytesSent) * 1000 /
(r.timestamp - old[id][r.type].timestamp)) * 8;
}
}
}