jiti-meet/modules/UI/videolayout/ConnectionIndicator.js

447 lines
15 KiB
JavaScript
Raw Normal View History

/* global APP, $, config */
/* jshint -W101 */
2015-12-14 12:26:50 +00:00
import JitsiPopover from "../util/JitsiPopover";
import VideoLayout from "./VideoLayout";
2015-01-07 14:54:03 +00:00
/**
* Constructs new connection indicator.
* @param videoContainer the video container associated with the indicator.
* @constructor
*/
2015-12-14 12:26:50 +00:00
function ConnectionIndicator(videoContainer, id) {
2015-01-07 14:54:03 +00:00
this.videoContainer = videoContainer;
this.bandwidth = null;
this.packetLoss = null;
this.bitrate = null;
this.showMoreValue = false;
this.resolution = null;
this.isResolutionHD = null;
2015-01-07 14:54:03 +00:00
this.transport = [];
this.popover = null;
2015-12-14 12:26:50 +00:00
this.id = id;
2015-01-07 14:54:03 +00:00
this.create();
}
/**
* Values for the connection quality
* @type {{98: string,
* 81: string,
* 64: string,
* 47: string,
* 30: string,
* 0: string}}
*/
ConnectionIndicator.connectionQualityValues = {
98: "18px", //full
81: "15px",//4 bars
64: "11px",//3 bars
47: "7px",//2 bars
30: "3px",//1 bar
0: "0px"//empty
};
ConnectionIndicator.getIP = function(value) {
2015-01-07 14:54:03 +00:00
return value.substring(0, value.lastIndexOf(":"));
};
ConnectionIndicator.getPort = function(value) {
2015-01-07 14:54:03 +00:00
return value.substring(value.lastIndexOf(":") + 1, value.length);
};
ConnectionIndicator.getStringFromArray = function (array) {
var res = "";
for(var i = 0; i < array.length; i++) {
2015-01-07 14:54:03 +00:00
res += (i === 0? "" : ", ") + array[i];
}
return res;
};
/**
* Generates the html content.
* @returns {string} the html content.
*/
ConnectionIndicator.prototype.generateText = function () {
2016-01-29 15:33:16 +00:00
var downloadBitrate, uploadBitrate, packetLoss, i;
2015-01-07 14:54:03 +00:00
var translate = APP.translation.translateString;
if(this.bitrate === null) {
2015-01-07 14:54:03 +00:00
downloadBitrate = "N/A";
uploadBitrate = "N/A";
}
else {
2015-01-07 14:54:03 +00:00
downloadBitrate =
this.bitrate.download? this.bitrate.download + " Kbps" : "N/A";
uploadBitrate =
this.bitrate.upload? this.bitrate.upload + " Kbps" : "N/A";
}
if(this.packetLoss === null) {
2015-01-07 14:54:03 +00:00
packetLoss = "N/A";
} else {
2015-01-07 14:54:03 +00:00
2016-10-20 10:43:05 +00:00
packetLoss = "<span class='connection-info__download'>&darr;</span>" +
(this.packetLoss.download !== null ?
this.packetLoss.download : "N/A") +
2016-10-20 10:43:05 +00:00
"% <span class='connection-info__upload'>&uarr;</span>" +
(this.packetLoss.upload !== null? this.packetLoss.upload : "N/A") +
"%";
2015-01-07 14:54:03 +00:00
}
2016-01-29 15:33:16 +00:00
// GENERATE RESOLUTIONS STRING
let resolutions = this.resolution || {};
let resolutionStr = Object.keys(resolutions).map(function (ssrc) {
let {width, height} = resolutions[ssrc];
return `${width}x${height}`;
}).join(', ') || 'N/A';
2015-01-07 14:54:03 +00:00
2016-10-13 15:00:02 +00:00
let result = (
2016-10-19 14:57:16 +00:00
`<table class="connection-info__container" style='width:100%'>
2016-10-13 15:00:02 +00:00
<tr>
<td>
<span data-i18n='connectionindicator.bitrate'>
${translate("connectionindicator.bitrate")}
</span>
</td>
<td>
2016-10-20 10:43:05 +00:00
<span class='connection-info__download'>&darr;</span>${downloadBitrate}
<span class='connection-info__upload'>&uarr;</span>${uploadBitrate}
2016-10-13 15:00:02 +00:00
</td>
</tr>
<tr>
<td>
<span data-i18n='connectionindicator.packetloss'>
${translate("connectionindicator.packetloss")}
</span>
</td>
<td>${packetLoss}</td>
</tr>
<tr>
<td>
<span data-i18n='connectionindicator.resolution'>
${translate("connectionindicator.resolution")}
</span>
</td>
<td>
${resolutionStr}
</td>
</tr>
</table>`);
2015-01-07 14:54:03 +00:00
2015-06-23 08:00:46 +00:00
if(this.videoContainer.videoSpanId == "localVideoContainer") {
result += "<a class=\"jitsipopover__showmore link\" " +
"onclick = \"APP.UI.connectionIndicatorShowMore('" +
2015-12-14 12:26:50 +00:00
// FIXME: we do not know local id when this text is generated
//this.id + "')\" data-i18n='connectionindicator." +
"local')\" data-i18n='connectionindicator." +
(this.showMoreValue ? "less" : "more") + "'>" +
translate("connectionindicator." + (this.showMoreValue ? "less" : "more")) +
"</a>";
}
2015-01-07 14:54:03 +00:00
if (this.showMoreValue) {
2015-01-07 14:54:03 +00:00
var downloadBandwidth, uploadBandwidth, transport;
if (this.bandwidth === null) {
2015-01-07 14:54:03 +00:00
downloadBandwidth = "N/A";
uploadBandwidth = "N/A";
} else {
2015-01-07 14:54:03 +00:00
downloadBandwidth = this.bandwidth.download?
this.bandwidth.download + " Kbps" :
"N/A";
uploadBandwidth = this.bandwidth.upload?
this.bandwidth.upload + " Kbps" :
"N/A";
}
if (!this.transport || this.transport.length === 0) {
2015-01-07 14:54:03 +00:00
transport = "<tr>" +
"<td><span " +
"data-i18n='connectionindicator.address'>" +
translate("connectionindicator.address") + "</span></td>" +
2015-01-07 14:54:03 +00:00
"<td> N/A</td></tr>";
} else {
2015-01-07 14:54:03 +00:00
var data = {remoteIP: [], localIP:[], remotePort:[], localPort:[]};
for(i = 0; i < this.transport.length; i++) {
2015-01-07 14:54:03 +00:00
var ip = ConnectionIndicator.getIP(this.transport[i].ip);
var port = ConnectionIndicator.getPort(this.transport[i].ip);
var localIP =
ConnectionIndicator.getIP(this.transport[i].localip);
var localPort =
ConnectionIndicator.getPort(this.transport[i].localip);
if(data.remoteIP.indexOf(ip) == -1) {
2015-01-07 14:54:03 +00:00
data.remoteIP.push(ip);
}
if(data.remotePort.indexOf(port) == -1) {
2015-01-07 14:54:03 +00:00
data.remotePort.push(port);
}
if(data.localIP.indexOf(localIP) == -1) {
2015-01-07 14:54:03 +00:00
data.localIP.push(localIP);
}
if(data.localPort.indexOf(localPort) == -1) {
2015-01-07 14:54:03 +00:00
data.localPort.push(localPort);
}
}
2015-02-27 17:58:05 +00:00
var local_address_key = "connectionindicator.localaddress";
var remote_address_key = "connectionindicator.remoteaddress";
2015-01-07 14:54:03 +00:00
var localTransport =
"<tr><td><span data-i18n='" +
2015-02-27 17:58:05 +00:00
local_address_key +"' data-i18n-options='" +
JSON.stringify({count: data.localIP.length}) + "'>" +
translate(local_address_key, {count: data.localIP.length}) +
"</span></td><td> " +
2015-01-07 14:54:03 +00:00
ConnectionIndicator.getStringFromArray(data.localIP) +
"</td></tr>";
transport =
"<tr><td><span data-i18n='" +
2015-02-27 17:58:05 +00:00
remote_address_key + "' data-i18n-options='" +
JSON.stringify({count: data.remoteIP.length}) + "'>" +
translate(remote_address_key,
{count: data.remoteIP.length}) +
"</span></td><td> " +
2015-01-07 14:54:03 +00:00
ConnectionIndicator.getStringFromArray(data.remoteIP) +
"</td></tr>";
2015-02-27 17:58:05 +00:00
var key_remote = "connectionindicator.remoteport",
key_local = "connectionindicator.localport";
2015-01-07 14:54:03 +00:00
transport += "<tr>" +
"<td>" +
"<span data-i18n='" + key_remote +
2015-02-27 17:58:05 +00:00
"' data-i18n-options='" +
JSON.stringify({count: this.transport.length}) + "'>" +
translate(key_remote, {count: this.transport.length}) +
"</span></td><td>";
localTransport += "<tr>" +
"<td>" +
"<span data-i18n='" + key_local +
2015-02-27 17:58:05 +00:00
"' data-i18n-options='" +
JSON.stringify({count: this.transport.length}) + "'>" +
translate(key_local, {count: this.transport.length}) +
"</span></td><td>";
2015-01-07 14:54:03 +00:00
transport +=
ConnectionIndicator.getStringFromArray(data.remotePort);
localTransport +=
ConnectionIndicator.getStringFromArray(data.localPort);
transport += "</td></tr>";
transport += localTransport + "</td></tr>";
transport +="<tr>" +
"<td><span data-i18n='connectionindicator.transport'>" +
translate("connectionindicator.transport") + "</span></td>" +
2015-01-07 14:54:03 +00:00
"<td>" + this.transport[0].type + "</td></tr>";
}
2016-10-19 14:57:16 +00:00
result += "<table class='connection-info__container' style='width:100%'>" +
2015-01-07 14:54:03 +00:00
"<tr>" +
"<td>" +
"<span data-i18n='connectionindicator.bandwidth'>" +
translate("connectionindicator.bandwidth") + "</span>" +
2015-01-07 14:54:03 +00:00
"</td><td>" +
2016-10-20 10:43:05 +00:00
"<span class='connection-info__download'>&darr;</span>" +
2015-01-07 14:54:03 +00:00
downloadBandwidth +
2016-10-20 10:43:05 +00:00
" <span class='connection-info__upload'>&uarr;</span>" +
2015-01-07 14:54:03 +00:00
uploadBandwidth + "</td></tr>";
result += transport + "</table>";
}
2016-10-13 15:00:02 +00:00
2015-01-07 14:54:03 +00:00
return result;
};
/**
* Shows or hide the additional information.
*/
ConnectionIndicator.prototype.showMore = function () {
this.showMoreValue = !this.showMoreValue;
this.updatePopoverData();
};
function createIcon(classes, iconClass) {
2015-01-07 14:54:03 +00:00
var icon = document.createElement("span");
for(var i in classes) {
2015-01-07 14:54:03 +00:00
icon.classList.add(classes[i]);
}
icon.appendChild(
document.createElement("i")).classList.add(iconClass);
2015-01-07 14:54:03 +00:00
return icon;
}
/**
* Creates the indicator
*/
ConnectionIndicator.prototype.create = function () {
this.connectionIndicatorContainer = document.createElement("div");
this.connectionIndicatorContainer.className = "connectionindicator";
this.connectionIndicatorContainer.style.display = "none";
this.videoContainer.container.appendChild(
this.connectionIndicatorContainer);
2015-01-07 14:54:03 +00:00
this.popover = new JitsiPopover(
2015-06-23 08:00:46 +00:00
$("#" + this.videoContainer.videoSpanId + " > .connectionindicator"),
2016-10-19 14:57:16 +00:00
{content: "<div class=\"connection-info\" data-i18n='connectionindicator.na'>" +
APP.translation.translateString("connectionindicator.na") + "</div>",
2015-01-07 14:54:03 +00:00
skin: "black"});
// override popover show method to make sure we will update the content
// before showing the popover
var origShowFunc = this.popover.show;
this.popover.show = function () {
// update content by forcing it, to finish even if popover
// is not visible
this.updatePopoverData(true);
// call the original show, passing its actual this
origShowFunc.call(this.popover);
}.bind(this);
2015-01-07 14:54:03 +00:00
this.emptyIcon = this.connectionIndicatorContainer.appendChild(
createIcon(["connection", "connection_empty"], "icon-connection"));
2015-01-07 14:54:03 +00:00
this.fullIcon = this.connectionIndicatorContainer.appendChild(
createIcon(["connection", "connection_full"], "icon-connection"));
this.interruptedIndicator = this.connectionIndicatorContainer.appendChild(
createIcon(["connection", "connection_lost"],"icon-connection-lost"));
$(this.interruptedIndicator).hide();
2015-01-07 14:54:03 +00:00
};
/**
* Removes the indicator
*/
ConnectionIndicator.prototype.remove = function() {
if (this.connectionIndicatorContainer.parentNode) {
this.connectionIndicatorContainer.parentNode.removeChild(
this.connectionIndicatorContainer);
}
2015-01-07 14:54:03 +00:00
this.popover.forceHide();
};
/**
* Updates the UI which displays warning about user's connectivity problems.
*
* @param {boolean} isActive true if the connection is working fine or false if
* the user is having connectivity issues.
*/
ConnectionIndicator.prototype.updateConnectionStatusIndicator
= function (isActive) {
this.isConnectionActive = isActive;
if (this.isConnectionActive) {
$(this.interruptedIndicator).hide();
$(this.emptyIcon).show();
$(this.fullIcon).show();
} else {
$(this.interruptedIndicator).show();
$(this.emptyIcon).hide();
$(this.fullIcon).hide();
this.updateConnectionQuality(0 /* zero bars */);
}
};
2015-01-07 14:54:03 +00:00
/**
* Updates the data of the indicator
* @param percent the percent of connection quality
* @param object the statistics data.
*/
ConnectionIndicator.prototype.updateConnectionQuality =
function (percent, object) {
if (percent === null) {
2015-01-07 14:54:03 +00:00
this.connectionIndicatorContainer.style.display = "none";
this.popover.forceHide();
return;
} else {
2015-01-07 14:54:03 +00:00
if(this.connectionIndicatorContainer.style.display == "none") {
this.connectionIndicatorContainer.style.display = "block";
}
}
if (object) {
this.bandwidth = object.bandwidth;
this.bitrate = object.bitrate;
this.packetLoss = object.packetLoss;
this.transport = object.transport;
if (object.resolution) {
this.resolution = object.resolution;
}
2015-01-07 14:54:03 +00:00
}
for (var quality in ConnectionIndicator.connectionQualityValues) {
if (percent >= quality) {
2015-01-07 14:54:03 +00:00
this.fullIcon.style.width =
ConnectionIndicator.connectionQualityValues[quality];
}
}
if (object && typeof object.isResolutionHD === 'boolean') {
this.isResolutionHD = object.isResolutionHD;
}
this.updateResolutionIndicator();
2015-01-07 14:54:03 +00:00
this.updatePopoverData();
};
/**
* Updates the resolution
* @param resolution the new resolution
*/
ConnectionIndicator.prototype.updateResolution = function (resolution) {
this.resolution = resolution;
this.updateResolutionIndicator();
2015-01-07 14:54:03 +00:00
this.updatePopoverData();
};
/**
* Updates the content of the popover if its visible
* @param force to work even if popover is not visible
2015-01-07 14:54:03 +00:00
*/
ConnectionIndicator.prototype.updatePopoverData = function (force) {
// generate content, translate it and add it to document only if
// popover is visible or we force to do so.
if(this.popover.popoverShown || force) {
this.popover.updateContent(
2016-10-19 14:57:16 +00:00
`<div class="connection-info">${this.generateText()}</div>`
);
2016-10-19 14:57:16 +00:00
APP.translation.translateElement($(".connection-info"));
}
2015-01-07 14:54:03 +00:00
};
/**
* Hides the popover
*/
ConnectionIndicator.prototype.hide = function () {
this.popover.forceHide();
};
/**
* Hides the indicator
*/
ConnectionIndicator.prototype.hideIndicator = function () {
this.connectionIndicatorContainer.style.display = "none";
if(this.popover)
this.popover.forceHide();
};
/**
* Updates the resolution indicator.
*/
ConnectionIndicator.prototype.updateResolutionIndicator = function () {
if (this.id !== null
&& VideoLayout.isCurrentlyOnLarge(this.id)) {
let showResolutionLabel = false;
if (this.isResolutionHD !== null)
showResolutionLabel = this.isResolutionHD;
else if (this.resolution !== null) {
let resolutions = this.resolution || {};
Object.keys(resolutions).map(function (ssrc) {
const { height } = resolutions[ssrc];
if (height >= config.minHDHeight)
showResolutionLabel = true;
});
}
VideoLayout.updateResolutionLabel(showResolutionLabel);
}
};
2015-12-14 12:26:50 +00:00
export default ConnectionIndicator;