mirror of
https://github.com/jech/galene.git
synced 2024-11-22 16:45:58 +01:00
Request low-resolution video when the video is small.
This commit is contained in:
parent
2da8faa8cf
commit
54cd546120
1 changed files with 136 additions and 3 deletions
139
static/galene.js
139
static/galene.js
|
@ -275,6 +275,7 @@ function hideVideo(force) {
|
||||||
if(mediadiv.childElementCount > 0 && !force)
|
if(mediadiv.childElementCount > 0 && !force)
|
||||||
return;
|
return;
|
||||||
setVisibility('video-container', false);
|
setVisibility('video-container', false);
|
||||||
|
scheduleReconsiderDownRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
function showVideo() {
|
function showVideo() {
|
||||||
|
@ -284,6 +285,7 @@ function showVideo() {
|
||||||
setVisibility('collapse-video', hasmedia);
|
setVisibility('collapse-video', hasmedia);
|
||||||
}
|
}
|
||||||
setVisibility('video-container', hasmedia);
|
setVisibility('video-container', hasmedia);
|
||||||
|
scheduleReconsiderDownRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
function fillLogin() {
|
function fillLogin() {
|
||||||
|
@ -305,12 +307,16 @@ function setConnected(connected) {
|
||||||
userbox.classList.remove('invisible');
|
userbox.classList.remove('invisible');
|
||||||
connectionbox.classList.add('invisible');
|
connectionbox.classList.add('invisible');
|
||||||
displayUsername();
|
displayUsername();
|
||||||
|
window.onresize = function(e) {
|
||||||
|
scheduleReconsiderDownRate();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fillLogin();
|
fillLogin();
|
||||||
userbox.classList.add('invisible');
|
userbox.classList.add('invisible');
|
||||||
connectionbox.classList.remove('invisible');
|
connectionbox.classList.remove('invisible');
|
||||||
displayError('Disconnected', 'error');
|
displayError('Disconnected', 'error');
|
||||||
hideVideo();
|
hideVideo();
|
||||||
|
window.onresize = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -580,17 +586,32 @@ function mapRequest(what) {
|
||||||
return {'': ['audio','video']}
|
return {'': ['audio','video']}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
displayError(`Unknown value ${what} in request`);
|
throw new Error(`Unknown value ${what} in request`);
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} what
|
||||||
|
* @param {string} label
|
||||||
|
* @returns {Array<string>}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function mapRequestLabel(what, label) {
|
||||||
|
let r = mapRequest(what);
|
||||||
|
if(label in r)
|
||||||
|
return r[label];
|
||||||
|
else
|
||||||
|
return r[''];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
getSelectElement('requestselect').onchange = function(e) {
|
getSelectElement('requestselect').onchange = function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if(!(this instanceof HTMLSelectElement))
|
if(!(this instanceof HTMLSelectElement))
|
||||||
throw new Error('Unexpected type for this');
|
throw new Error('Unexpected type for this');
|
||||||
updateSettings({request: this.value});
|
updateSettings({request: this.value});
|
||||||
serverConnection.request(mapRequest(this.value));
|
serverConnection.request(mapRequest(this.value));
|
||||||
|
reconsiderDownRate();
|
||||||
};
|
};
|
||||||
|
|
||||||
const activityDetectionInterval = 200;
|
const activityDetectionInterval = 200;
|
||||||
|
@ -1482,6 +1503,113 @@ function muteLocalTracks(mute) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} id
|
||||||
|
* @param {boolean} force
|
||||||
|
* @param {boolean} [value]
|
||||||
|
*/
|
||||||
|
function forceDownRate(id, force, value) {
|
||||||
|
let c = serverConnection.down[id];
|
||||||
|
if(!c)
|
||||||
|
throw new Error("Unknown down stream");
|
||||||
|
if('requested' in c.userdata) {
|
||||||
|
if(force)
|
||||||
|
c.userdata.requested.force = !!value;
|
||||||
|
else
|
||||||
|
delete(c.userdata.requested.force);
|
||||||
|
} else {
|
||||||
|
if(force)
|
||||||
|
c.userdata.requested = {force: value};
|
||||||
|
}
|
||||||
|
reconsiderDownRate(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps 'video' to 'video-low'. Returns null if nothing changed.
|
||||||
|
*
|
||||||
|
* @param {string[]} requested
|
||||||
|
* @returns {string[]}
|
||||||
|
*/
|
||||||
|
function mapVideoToLow(requested) {
|
||||||
|
let result = [];
|
||||||
|
let found = false;
|
||||||
|
for(let i = 0; i < requested.length; i++) {
|
||||||
|
let r = requested[i];
|
||||||
|
if(r === 'video') {
|
||||||
|
r = 'video-low';
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
result.push(r);
|
||||||
|
}
|
||||||
|
if(!found)
|
||||||
|
return null;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reconsider the video track requested for a given down stream.
|
||||||
|
*
|
||||||
|
* @param {string} [id] - the id of the track to reconsider, all if null.
|
||||||
|
*/
|
||||||
|
function reconsiderDownRate(id) {
|
||||||
|
if(!serverConnection)
|
||||||
|
return;
|
||||||
|
if(!id) {
|
||||||
|
for(let id in serverConnection.down) {
|
||||||
|
reconsiderDownRate(id);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let c = serverConnection.down[id];
|
||||||
|
if(!c)
|
||||||
|
throw new Error("Unknown down stream");
|
||||||
|
let normalrequest = mapRequestLabel(getSettings().request, c.label);
|
||||||
|
|
||||||
|
let requestlow = mapVideoToLow(normalrequest);
|
||||||
|
if(requestlow === null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let old = c.userdata.requested;
|
||||||
|
let low = false;
|
||||||
|
if(old && ('force' in old)) {
|
||||||
|
low = old.force;
|
||||||
|
} else {
|
||||||
|
let media = /** @type {HTMLVideoElement} */
|
||||||
|
(document.getElementById('media-' + c.localId));
|
||||||
|
if(!media)
|
||||||
|
throw new Error("No media for stream");
|
||||||
|
let w = media.scrollWidth;
|
||||||
|
let h = media.scrollHeight;
|
||||||
|
if(w && h && w * h <= 320 * 240) {
|
||||||
|
low = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(low !== !!(old && old.low)) {
|
||||||
|
if('requested' in c.userdata)
|
||||||
|
c.userdata.requested.low = low;
|
||||||
|
else
|
||||||
|
c.userdata.requested = {low: low};
|
||||||
|
c.request(low ? requestlow : null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let reconsiderDownRateTimer = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules reconsiderDownRate() to be run later. The delay avoids too
|
||||||
|
* much recomputations when resizing the window.
|
||||||
|
*/
|
||||||
|
function scheduleReconsiderDownRate() {
|
||||||
|
if(reconsiderDownRateTimer)
|
||||||
|
return;
|
||||||
|
reconsiderDownRateTimer =
|
||||||
|
setTimeout(() => {
|
||||||
|
reconsiderDownRateTimer = null;
|
||||||
|
reconsiderDownRate();
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* setMedia adds a new media element corresponding to stream c.
|
* setMedia adds a new media element corresponding to stream c.
|
||||||
*
|
*
|
||||||
|
@ -1533,6 +1661,12 @@ async function setMedia(c, isUp, mirror, video) {
|
||||||
if(!video && media.srcObject !== c.stream)
|
if(!video && media.srcObject !== c.stream)
|
||||||
media.srcObject = c.stream;
|
media.srcObject = c.stream;
|
||||||
|
|
||||||
|
if(!isUp) {
|
||||||
|
media.onfullscreenchange = function(e) {
|
||||||
|
forceDownRate(c.id, document.fullscreenElement === media, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let label = document.getElementById('label-' + c.localId);
|
let label = document.getElementById('label-' + c.localId);
|
||||||
if(!label) {
|
if(!label) {
|
||||||
label = document.createElement('div');
|
label = document.createElement('div');
|
||||||
|
@ -2936,7 +3070,6 @@ function start() {
|
||||||
|
|
||||||
fillLogin();
|
fillLogin();
|
||||||
document.getElementById("login-container").classList.remove('invisible');
|
document.getElementById("login-container").classList.remove('invisible');
|
||||||
|
|
||||||
setViewportHeight();
|
setViewportHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue