mirror of
https://github.com/jech/galene.git
synced 2024-11-22 16:45:58 +01:00
WIP
This commit is contained in:
parent
5722270cc7
commit
300d6e2e9d
2 changed files with 97 additions and 97 deletions
|
@ -214,16 +214,19 @@
|
||||||
<option value="lowest">lowest</option>
|
<option value="lowest">lowest</option>
|
||||||
<option value="low">low</option>
|
<option value="low">low</option>
|
||||||
<option value="normal" selected>normal</option>
|
<option value="normal" selected>normal</option>
|
||||||
<option value="unlimited">unlimited</option>
|
<option value="high">high</option>
|
||||||
|
<option value="highest">highest</option>
|
||||||
</select>
|
</select>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<form id="simulcastform">
|
<form id="scalabilityform">
|
||||||
<label for="simulcastselect" class="sidenav-label-first">Simulcast:</label>
|
<label for="scalabilityselect" class="sidenav-label-first">Scalability mode:</label>
|
||||||
<select id="simulcastselect" class="select select-inline">
|
<select id="scalabilityselect" class="select select-inline">
|
||||||
<option value="off">off</option>
|
<option value="off">off</option>
|
||||||
<option value="auto" selected>auto</option>
|
<option value="auto" selected>auto</option>
|
||||||
<option value="on">on</option>
|
<option value="svc">SVC</option>
|
||||||
|
<option value="simulcast">simulcast</option>
|
||||||
|
<option value="both">both</option>
|
||||||
</select>
|
</select>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|
181
static/galene.js
181
static/galene.js
|
@ -40,7 +40,7 @@ let connectingAgain = false;
|
||||||
* @property {boolean} [localMute]
|
* @property {boolean} [localMute]
|
||||||
* @property {string} [video]
|
* @property {string} [video]
|
||||||
* @property {string} [audio]
|
* @property {string} [audio]
|
||||||
* @property {string} [simulcast]
|
* @property {string} [scalability]
|
||||||
* @property {string} [send]
|
* @property {string} [send]
|
||||||
* @property {string} [request]
|
* @property {string} [request]
|
||||||
* @property {boolean} [activityDetection]
|
* @property {boolean} [activityDetection]
|
||||||
|
@ -195,10 +195,10 @@ function reflectSettings() {
|
||||||
store = true;
|
store = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(settings.hasOwnProperty('simulcast')) {
|
if(settings.hasOwnProperty('scalability')) {
|
||||||
getSelectElement('simulcastselect').value = settings.simulcast
|
getSelectElement('scalabilityselect').value = settings.scalability;
|
||||||
} else {
|
} else {
|
||||||
settings.simulcast = getSelectElement('simulcastselect').value;
|
settings.scalability = getSelectElement('scalabilityselect').value;
|
||||||
store = true;
|
store = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,11 +280,6 @@ function isSafari() {
|
||||||
return ua.indexOf('safari') >= 0 && ua.indexOf('chrome') < 0;
|
return ua.indexOf('safari') >= 0 && ua.indexOf('chrome') < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isFirefox() {
|
|
||||||
let ua = navigator.userAgent.toLowerCase();
|
|
||||||
return ua.indexOf('firefox') >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @type {MediaStream} */
|
/** @type {MediaStream} */
|
||||||
let safariStream = null;
|
let safariStream = null;
|
||||||
|
|
||||||
|
@ -496,7 +491,7 @@ function setButtonsVisibility() {
|
||||||
|
|
||||||
setVisibility('mediaoptions', present);
|
setVisibility('mediaoptions', present);
|
||||||
setVisibility('sendform', present);
|
setVisibility('sendform', present);
|
||||||
setVisibility('simulcastform', present);
|
setVisibility('scalabilityform', present);
|
||||||
|
|
||||||
setVisibility('collapse-video', mediacount && mobilelayout);
|
setVisibility('collapse-video', mediacount && mobilelayout);
|
||||||
}
|
}
|
||||||
|
@ -598,24 +593,6 @@ getSelectElement('filterselect').onchange = async function(e) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @returns {number} */
|
|
||||||
function getMaxVideoThroughput() {
|
|
||||||
let v = getSettings().send;
|
|
||||||
switch(v) {
|
|
||||||
case 'lowest':
|
|
||||||
return 150000;
|
|
||||||
case 'low':
|
|
||||||
return 300000;
|
|
||||||
case 'normal':
|
|
||||||
return 700000;
|
|
||||||
case 'unlimited':
|
|
||||||
return null;
|
|
||||||
default:
|
|
||||||
console.error('Unknown video quality', v);
|
|
||||||
return 700000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getSelectElement('sendselect').onchange = async function(e) {
|
getSelectElement('sendselect').onchange = async function(e) {
|
||||||
if(!(this instanceof HTMLSelectElement))
|
if(!(this instanceof HTMLSelectElement))
|
||||||
throw new Error('Unexpected type for this');
|
throw new Error('Unexpected type for this');
|
||||||
|
@ -623,10 +600,10 @@ getSelectElement('sendselect').onchange = async function(e) {
|
||||||
await reconsiderSendParameters();
|
await reconsiderSendParameters();
|
||||||
};
|
};
|
||||||
|
|
||||||
getSelectElement('simulcastselect').onchange = async function(e) {
|
getSelectElement('scalabilityselect').onchange = async function(e) {
|
||||||
if(!(this instanceof HTMLSelectElement))
|
if(!(this instanceof HTMLSelectElement))
|
||||||
throw new Error('Unexpected type for this');
|
throw new Error('Unexpected type for this');
|
||||||
updateSettings({simulcast: this.value});
|
updateSettings({scalability: this.value});
|
||||||
await reconsiderSendParameters();
|
await reconsiderSendParameters();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -908,14 +885,78 @@ function newUpStream(localId) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const simulcastRate = 100000;
|
||||||
|
const hqAudioRate = 128000;
|
||||||
|
const videoRates = {
|
||||||
|
lowest: 150000,
|
||||||
|
low: 300000,
|
||||||
|
normal: 700000,
|
||||||
|
high: 1500000,
|
||||||
|
highest: 3000000,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an up stream's video throughput and simulcast parameters.
|
* @typedef {Object} sendParameters
|
||||||
|
* @property {number} maxBitrate
|
||||||
|
* @property {string} scalabilityMode
|
||||||
|
* @property {boolean} simulcast
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {sendParameters}
|
||||||
|
*/
|
||||||
|
function getSendParameters() {
|
||||||
|
let bps = videoRates[getSettings().send];
|
||||||
|
if(!bps) {
|
||||||
|
console.error('Unknown video quality');
|
||||||
|
bps = 700000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type{sendParameters} */
|
||||||
|
let parms = {
|
||||||
|
maxBitrate: bps,
|
||||||
|
scalabilityMode: 'L1T1',
|
||||||
|
simulcast: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(getSettings().scalability) {
|
||||||
|
case 'off':
|
||||||
|
return parms;
|
||||||
|
case 'svc':
|
||||||
|
parms.scalabilityMode = 'L3T3';
|
||||||
|
return parms;
|
||||||
|
case 'simulcast':
|
||||||
|
parms.simulcast = true;
|
||||||
|
return parms;
|
||||||
|
case 'both':
|
||||||
|
parms.scalabilityMode = 'L1T3';
|
||||||
|
parms.simulcast = true;
|
||||||
|
return parms;
|
||||||
|
default:
|
||||||
|
let count = 0;
|
||||||
|
for(let n in serverConnection.users) {
|
||||||
|
if(!serverConnection.users[n].permissions["system"]) {
|
||||||
|
count++;
|
||||||
|
if(count > 2)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(count <= 2)
|
||||||
|
return parms;
|
||||||
|
if(!bps || bps < 2 * simulcastRate)
|
||||||
|
return parms;
|
||||||
|
parms.scalabilityMode = 'L3T3';
|
||||||
|
return parms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets an up stream's video throughput and scalability parameters.
|
||||||
*
|
*
|
||||||
* @param {Stream} c
|
* @param {Stream} c
|
||||||
* @param {number} bps
|
* @param {sendParameters} parms
|
||||||
* @param {boolean} simulcast
|
|
||||||
*/
|
*/
|
||||||
async function setSendParameters(c, bps, simulcast) {
|
async function setSendParameters(c, parms) {
|
||||||
if(!c.up)
|
if(!c.up)
|
||||||
throw new Error('Setting throughput of down stream');
|
throw new Error('Setting throughput of down stream');
|
||||||
let senders = c.pc.getSenders();
|
let senders = c.pc.getSenders();
|
||||||
|
@ -925,14 +966,15 @@ async function setSendParameters(c, bps, simulcast) {
|
||||||
continue;
|
continue;
|
||||||
let p = s.getParameters();
|
let p = s.getParameters();
|
||||||
if((!p.encodings ||
|
if((!p.encodings ||
|
||||||
!simulcast && p.encodings.length != 1) ||
|
!parms.simulcast && p.encodings.length != 1) ||
|
||||||
(simulcast && p.encodings.length != 2)) {
|
(parms.simulcast && p.encodings.length < 2)) {
|
||||||
await replaceUpStream(c);
|
await replaceUpStream(c);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p.encodings.forEach(e => {
|
p.encodings.forEach(e => {
|
||||||
if(!e.rid || e.rid === 'h')
|
if(!e.rid || e.rid === 'h')
|
||||||
e.maxBitrate = bps || unlimitedRate;
|
e.maxBitrate = parms.maxBitrate;
|
||||||
|
e.scalabilityMode = parms.scalabilityMode;
|
||||||
});
|
});
|
||||||
await s.setParameters(p);
|
await s.setParameters(p);
|
||||||
}
|
}
|
||||||
|
@ -945,12 +987,11 @@ let reconsiderParametersTimer = null;
|
||||||
*/
|
*/
|
||||||
async function reconsiderSendParameters() {
|
async function reconsiderSendParameters() {
|
||||||
cancelReconsiderParameters();
|
cancelReconsiderParameters();
|
||||||
let t = getMaxVideoThroughput();
|
let parms = getSendParameters();
|
||||||
let s = doSimulcast();
|
|
||||||
let promises = [];
|
let promises = [];
|
||||||
for(let id in serverConnection.up) {
|
for(let id in serverConnection.up) {
|
||||||
let c = serverConnection.up[id];
|
let c = serverConnection.up[id];
|
||||||
promises.push(setSendParameters(c, t, s));
|
promises.push(setSendParameters(c, parms));
|
||||||
}
|
}
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
@ -1167,37 +1208,6 @@ function addFilters() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const unlimitedRate = 1000000000;
|
|
||||||
const simulcastRate = 100000;
|
|
||||||
const hqAudioRate = 128000;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decide whether we want to send simulcast.
|
|
||||||
*
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
function doSimulcast() {
|
|
||||||
switch(getSettings().simulcast) {
|
|
||||||
case 'on':
|
|
||||||
return true;
|
|
||||||
case 'off':
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
let count = 0;
|
|
||||||
for(let n in serverConnection.users) {
|
|
||||||
if(!serverConnection.users[n].permissions["system"]) {
|
|
||||||
count++;
|
|
||||||
if(count > 2)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(count <= 2)
|
|
||||||
return false;
|
|
||||||
let bps = getMaxVideoThroughput();
|
|
||||||
return bps <= 0 || bps >= 2 * simulcastRate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up c to send the given stream. Some extra parameters are stored
|
* Sets up c to send the given stream. Some extra parameters are stored
|
||||||
* in c.userdata.
|
* in c.userdata.
|
||||||
|
@ -1250,24 +1260,26 @@ function setUpStream(c, stream) {
|
||||||
};
|
};
|
||||||
|
|
||||||
let encodings = [];
|
let encodings = [];
|
||||||
let simulcast = doSimulcast();
|
let parms = getSendParameters();
|
||||||
if(t.kind === 'video') {
|
if(t.kind === 'video') {
|
||||||
let bps = getMaxVideoThroughput();
|
|
||||||
// Firefox doesn't like us setting the RID if we're not
|
// Firefox doesn't like us setting the RID if we're not
|
||||||
// simulcasting.
|
// simulcasting.
|
||||||
if(simulcast && c.label !== 'screenshare') {
|
if(parms.simulcast) {
|
||||||
encodings.push({
|
encodings.push({
|
||||||
rid: 'h',
|
rid: 'h',
|
||||||
maxBitrate: bps || unlimitedRate,
|
maxBitrate: parms.maxBitrate,
|
||||||
|
scalabilityMode: parms.scalabilityMode,
|
||||||
});
|
});
|
||||||
encodings.push({
|
encodings.push({
|
||||||
rid: 'l',
|
rid: 'l',
|
||||||
scaleResolutionDownBy: 2,
|
scaleResolutionDownBy: 2,
|
||||||
maxBitrate: simulcastRate,
|
maxBitrate: simulcastRate,
|
||||||
|
scalabilityMode: parms.scalabilityMode,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
encodings.push({
|
encodings.push({
|
||||||
maxBitrate: bps || unlimitedRate,
|
maxBitrate: parms.maxBitrate,
|
||||||
|
scalabilityMode: parms.scalabilityMode,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1277,22 +1289,11 @@ function setUpStream(c, stream) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let tr = c.pc.addTransceiver(t, {
|
c.pc.addTransceiver(t, {
|
||||||
direction: 'sendonly',
|
direction: 'sendonly',
|
||||||
streams: [stream],
|
streams: [stream],
|
||||||
sendEncodings: encodings,
|
sendEncodings: encodings,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Firefox before 110 does not implement sendEncodings, and
|
|
||||||
// requires this hack, which throws an exception on Chromium.
|
|
||||||
try {
|
|
||||||
let p = tr.sender.getParameters();
|
|
||||||
if(!p.encodings) {
|
|
||||||
p.encodings = encodings;
|
|
||||||
tr.sender.setParameters(p);
|
|
||||||
}
|
|
||||||
} catch(e) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// c.stream might be different from stream if there's a filter
|
// c.stream might be different from stream if there's a filter
|
||||||
|
@ -3923,10 +3924,6 @@ async function start() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable simulcast on Firefox by default, it's buggy.
|
|
||||||
if(isFirefox())
|
|
||||||
getSelectElement('simulcastselect').value = 'off';
|
|
||||||
|
|
||||||
let parms = new URLSearchParams(window.location.search);
|
let parms = new URLSearchParams(window.location.search);
|
||||||
if(window.location.search)
|
if(window.location.search)
|
||||||
window.history.replaceState(null, '', window.location.pathname);
|
window.history.replaceState(null, '', window.location.pathname);
|
||||||
|
|
Loading…
Reference in a new issue