Calculates quality based on the resolution and upload.
This commit is contained in:
parent
d5541f612f
commit
a2c71d05e6
|
@ -1372,7 +1372,8 @@ export default {
|
|||
}
|
||||
|
||||
room.on(ConferenceEvents.CONNECTION_STATS, function (stats) {
|
||||
ConnectionQuality.updateLocalStats(stats, connectionIsInterrupted);
|
||||
ConnectionQuality.updateLocalStats(
|
||||
stats, connectionIsInterrupted, localVideo);
|
||||
});
|
||||
|
||||
ConnectionQuality.addListener(CQEvents.LOCALSTATS_UPDATED,
|
||||
|
@ -1382,6 +1383,12 @@ export default {
|
|||
let data = {
|
||||
bitrate: stats.bitrate,
|
||||
packetLoss: stats.packetLoss};
|
||||
if (localVideo && localVideo.resolution) {
|
||||
data.resolution = {
|
||||
inputHeight: localVideo.resolution
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
room.broadcastEndpointMessage({
|
||||
type: this.commands.defaults.CONNECTION_QUALITY,
|
||||
|
@ -1394,10 +1401,15 @@ export default {
|
|||
room.on(ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
|
||||
(participant, payload) => {
|
||||
switch(payload.type) {
|
||||
case this.commands.defaults.CONNECTION_QUALITY:
|
||||
ConnectionQuality.updateRemoteStats(participant.getId(),
|
||||
payload.values);
|
||||
case this.commands.defaults.CONNECTION_QUALITY: {
|
||||
let id = participant.getId();
|
||||
ConnectionQuality.updateRemoteStats(
|
||||
id,
|
||||
payload.values,
|
||||
APP.UI.getRemoteVideoType(id),
|
||||
APP.UI.isRemoteVideoMuted(id));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console.warn("Unknown datachannel message", payload);
|
||||
}
|
||||
|
|
|
@ -779,6 +779,15 @@ UI.getRemoteVideoType = function (jid) {
|
|||
return VideoLayout.getRemoteVideoType(jid);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the mute state of the remote video.
|
||||
* @param jid the jid for the remote video
|
||||
* @returns the video mute state.
|
||||
*/
|
||||
UI.isRemoteVideoMuted = function (jid) {
|
||||
return VideoLayout.isRemoteVideoMuted(jid);
|
||||
};
|
||||
|
||||
UI.connectionIndicatorShowMore = function(id) {
|
||||
VideoLayout.showMore(id);
|
||||
};
|
||||
|
|
|
@ -327,6 +327,16 @@ var VideoLayout = {
|
|||
return smallVideo ? smallVideo.getVideoType() : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the mute state of the remote video.
|
||||
* @param id the id for the remote video
|
||||
* @returns {boolean} the video mute state.
|
||||
*/
|
||||
isRemoteVideoMuted (id) {
|
||||
let smallVideo = VideoLayout.getSmallVideo(id);
|
||||
return smallVideo ? smallVideo.isVideoMuted : null;
|
||||
},
|
||||
|
||||
isPinned (id) {
|
||||
return (pinnedId) ? (id === pinnedId) : false;
|
||||
},
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* global config */
|
||||
import EventEmitter from "events";
|
||||
|
||||
import CQEvents from "../../service/connectionquality/CQEvents";
|
||||
|
@ -35,6 +36,58 @@ function calculateQuality(newVal, oldVal) {
|
|||
return (newVal <= oldVal) ? newVal : (9*oldVal + newVal) / 10;
|
||||
}
|
||||
|
||||
// webrtc table describing simulcast resolutions and used bandwidth
|
||||
// https://chromium.googlesource.com/external/webrtc/+/master/webrtc/media/engine/simulcast.cc#42
|
||||
var _bandwidthMap = [
|
||||
{ width: 1920, height: 1080, layers:3, max: 5000, min: 800 },
|
||||
{ width: 1280, height: 720, layers:3, max: 2500, min: 600 },
|
||||
{ width: 960, height: 540, layers:3, max: 900, min: 450 },
|
||||
{ width: 640, height: 360, layers:2, max: 700, min: 150 },
|
||||
{ width: 480, height: 270, layers:2, max: 450, min: 150 },
|
||||
{ width: 320, height: 180, layers:1, max: 200, min: 30 }
|
||||
];
|
||||
|
||||
/**
|
||||
* We disable quality calculations based on bandwidth if simulcast is disabled,
|
||||
* or enable it in case of no simulcast and we force it.
|
||||
* @type {boolean}
|
||||
*/
|
||||
var disableQualityBasedOnBandwidth =
|
||||
config.forceQualityBasedOnBandwidth ? false : config.disableSimulcast;
|
||||
|
||||
/**
|
||||
* Calculates the quality percentage based on the input resolution height and
|
||||
* the upload reported by the client. The value is based on the interval from
|
||||
* _bandwidthMap.
|
||||
* @param inputHeight the resolution used to open the camera.
|
||||
* @param upload the upload rate reported by client.
|
||||
* @returns {*} the percent of upload based on _bandwidthMap and maximum value
|
||||
* of 100, as values of the map are approximate and clients can stream above
|
||||
* those values.
|
||||
*/
|
||||
function calculateQualityUsingUpload(inputHeight, upload) {
|
||||
let foundResolution = null;
|
||||
|
||||
for (let i in _bandwidthMap) {
|
||||
let r = _bandwidthMap[i];
|
||||
if (r.height <= inputHeight) {
|
||||
foundResolution = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundResolution)
|
||||
return false;
|
||||
|
||||
if (upload <= foundResolution.min)
|
||||
return 0;
|
||||
|
||||
return Math.min(
|
||||
((upload - foundResolution.min)*100)
|
||||
/ (foundResolution.max - foundResolution.min),
|
||||
100);
|
||||
}
|
||||
|
||||
export default {
|
||||
/**
|
||||
* Updates the local statistics
|
||||
|
@ -42,15 +95,28 @@ export default {
|
|||
* @param dontUpdateLocalConnectionQuality {boolean} if true -
|
||||
* localConnectionQuality wont be recalculated.
|
||||
*/
|
||||
updateLocalStats: function (data, dontUpdateLocalConnectionQuality) {
|
||||
stats = data;
|
||||
if(!dontUpdateLocalConnectionQuality) {
|
||||
var newVal = 100 - stats.packetLoss.total;
|
||||
localConnectionQuality =
|
||||
calculateQuality(newVal, localConnectionQuality);
|
||||
}
|
||||
eventEmitter.emit(CQEvents.LOCALSTATS_UPDATED, localConnectionQuality,
|
||||
stats);
|
||||
updateLocalStats:
|
||||
function (data, dontUpdateLocalConnectionQuality, localVideo) {
|
||||
stats = data;
|
||||
if(!dontUpdateLocalConnectionQuality) {
|
||||
if (!disableQualityBasedOnBandwidth
|
||||
&& !localVideo.isMuted()
|
||||
&& localVideo.videoType !== 'desktop'
|
||||
&& localVideo.resolution) {
|
||||
let val = calculateQualityUsingUpload(
|
||||
localVideo.resolution,
|
||||
data.bitrate.upload);
|
||||
if (val) {
|
||||
localConnectionQuality = val;
|
||||
}
|
||||
} else {
|
||||
var newVal = 100 - stats.packetLoss.total;
|
||||
localConnectionQuality =
|
||||
calculateQuality(newVal, localConnectionQuality);
|
||||
}
|
||||
}
|
||||
eventEmitter.emit(
|
||||
CQEvents.LOCALSTATS_UPDATED, localConnectionQuality, stats);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -68,23 +134,41 @@ export default {
|
|||
* @param id the id associated with the statistics
|
||||
* @param data the statistics
|
||||
*/
|
||||
updateRemoteStats: function (id, data) {
|
||||
if (!data || !("packetLoss" in data) || !("total" in data.packetLoss)) {
|
||||
eventEmitter.emit(CQEvents.REMOTESTATS_UPDATED, id, null, null);
|
||||
return;
|
||||
}
|
||||
// Use only the fields we need
|
||||
data = {bitrate: data.bitrate, packetLoss: data.packetLoss};
|
||||
updateRemoteStats:
|
||||
function (id, data, remoteVideoType, isRemoteVideoMuted) {
|
||||
if (!data ||
|
||||
!("packetLoss" in data) ||
|
||||
!("total" in data.packetLoss)) {
|
||||
eventEmitter.emit(CQEvents.REMOTESTATS_UPDATED, id, null, null);
|
||||
return;
|
||||
}
|
||||
|
||||
remoteStats[id] = data;
|
||||
let inputResolution = data.resolution;
|
||||
// Use only the fields we need
|
||||
data = {bitrate: data.bitrate, packetLoss: data.packetLoss};
|
||||
|
||||
var newVal = 100 - data.packetLoss.total;
|
||||
var oldVal = remoteConnectionQuality[id];
|
||||
remoteConnectionQuality[id] = calculateQuality(newVal, oldVal || 100);
|
||||
remoteStats[id] = data;
|
||||
|
||||
eventEmitter.emit(
|
||||
CQEvents.REMOTESTATS_UPDATED, id, remoteConnectionQuality[id],
|
||||
remoteStats[id]);
|
||||
if (disableQualityBasedOnBandwidth
|
||||
|| isRemoteVideoMuted
|
||||
|| remoteVideoType === 'desktop'
|
||||
|| !inputResolution) {
|
||||
var newVal = 100 - data.packetLoss.total;
|
||||
var oldVal = remoteConnectionQuality[id];
|
||||
remoteConnectionQuality[id]
|
||||
= calculateQuality(newVal, oldVal || 100);
|
||||
} else {
|
||||
let val = calculateQualityUsingUpload(
|
||||
inputResolution.inputHeight,
|
||||
data.bitrate.upload);
|
||||
if (val) {
|
||||
remoteConnectionQuality[id] = val;
|
||||
}
|
||||
}
|
||||
|
||||
eventEmitter.emit(
|
||||
CQEvents.REMOTESTATS_UPDATED, id,
|
||||
remoteConnectionQuality[id], remoteStats[id]);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue