Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

ConnectionIndicator.js 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. var JitsiPopover = require("../util/JitsiPopover");
  2. /**
  3. * Constructs new connection indicator.
  4. * @param videoContainer the video container associated with the indicator.
  5. * @constructor
  6. */
  7. function ConnectionIndicator(videoContainer, jid, VideoLayout)
  8. {
  9. this.videoContainer = videoContainer;
  10. this.bandwidth = null;
  11. this.packetLoss = null;
  12. this.bitrate = null;
  13. this.showMoreValue = false;
  14. this.resolution = null;
  15. this.transport = [];
  16. this.popover = null;
  17. this.jid = jid;
  18. this.create();
  19. this.videoLayout = VideoLayout;
  20. }
  21. /**
  22. * Values for the connection quality
  23. * @type {{98: string,
  24. * 81: string,
  25. * 64: string,
  26. * 47: string,
  27. * 30: string,
  28. * 0: string}}
  29. */
  30. ConnectionIndicator.connectionQualityValues = {
  31. 98: "18px", //full
  32. 81: "15px",//4 bars
  33. 64: "11px",//3 bars
  34. 47: "7px",//2 bars
  35. 30: "3px",//1 bar
  36. 0: "0px"//empty
  37. };
  38. ConnectionIndicator.getIP = function(value)
  39. {
  40. return value.substring(0, value.lastIndexOf(":"));
  41. };
  42. ConnectionIndicator.getPort = function(value)
  43. {
  44. return value.substring(value.lastIndexOf(":") + 1, value.length);
  45. };
  46. ConnectionIndicator.getStringFromArray = function (array) {
  47. var res = "";
  48. for(var i = 0; i < array.length; i++)
  49. {
  50. res += (i === 0? "" : ", ") + array[i];
  51. }
  52. return res;
  53. };
  54. /**
  55. * Generates the html content.
  56. * @returns {string} the html content.
  57. */
  58. ConnectionIndicator.prototype.generateText = function () {
  59. var downloadBitrate, uploadBitrate, packetLoss, resolution, i;
  60. if(this.bitrate === null)
  61. {
  62. downloadBitrate = "N/A";
  63. uploadBitrate = "N/A";
  64. }
  65. else
  66. {
  67. downloadBitrate =
  68. this.bitrate.download? this.bitrate.download + " Kbps" : "N/A";
  69. uploadBitrate =
  70. this.bitrate.upload? this.bitrate.upload + " Kbps" : "N/A";
  71. }
  72. if(this.packetLoss === null)
  73. {
  74. packetLoss = "N/A";
  75. }
  76. else
  77. {
  78. packetLoss = "<span class='jitsipopover_green'>&darr;</span>" +
  79. (this.packetLoss.download !== null? this.packetLoss.download : "N/A") +
  80. "% <span class='jitsipopover_orange'>&uarr;</span>" +
  81. (this.packetLoss.upload !== null? this.packetLoss.upload : "N/A") + "%";
  82. }
  83. var resolutionValue = null;
  84. if(this.resolution && this.jid != null)
  85. {
  86. var keys = Object.keys(this.resolution);
  87. if(keys.length == 1)
  88. {
  89. for(var ssrc in this.resolution)
  90. {
  91. resolutionValue = this.resolution[ssrc];
  92. }
  93. }
  94. else if(keys.length > 1)
  95. {
  96. var displayedSsrc = APP.simulcast.getReceivingSSRC(this.jid);
  97. resolutionValue = this.resolution[displayedSsrc];
  98. }
  99. }
  100. if(this.jid === null)
  101. {
  102. resolution = "";
  103. if(this.resolution === null || !Object.keys(this.resolution) ||
  104. Object.keys(this.resolution).length === 0)
  105. {
  106. resolution = "N/A";
  107. }
  108. else
  109. for(i in this.resolution)
  110. {
  111. resolutionValue = this.resolution[i];
  112. if(resolutionValue)
  113. {
  114. if(resolutionValue.height &&
  115. resolutionValue.width)
  116. {
  117. resolution += (resolution === ""? "" : ", ") +
  118. resolutionValue.width + "x" +
  119. resolutionValue.height;
  120. }
  121. }
  122. }
  123. }
  124. else if(!resolutionValue ||
  125. !resolutionValue.height ||
  126. !resolutionValue.width)
  127. {
  128. resolution = "N/A";
  129. }
  130. else
  131. {
  132. resolution = resolutionValue.width + "x" + resolutionValue.height;
  133. }
  134. var result = "<table style='width:100%'>" +
  135. "<tr>" +
  136. "<td><span class='jitsipopover_blue'>Bitrate:</span></td>" +
  137. "<td><span class='jitsipopover_green'>&darr;</span>" +
  138. downloadBitrate + " <span class='jitsipopover_orange'>&uarr;</span>" +
  139. uploadBitrate + "</td>" +
  140. "</tr><tr>" +
  141. "<td><span class='jitsipopover_blue'>Packet loss: </span></td>" +
  142. "<td>" + packetLoss + "</td>" +
  143. "</tr><tr>" +
  144. "<td><span class='jitsipopover_blue'>Resolution:</span></td>" +
  145. "<td>" + resolution + "</td></tr></table>";
  146. if(this.videoContainer.id == "localVideoContainer")
  147. result += "<div class=\"jitsipopover_showmore\" " +
  148. "onclick = \"APP.UI.connectionIndicatorShowMore('" +
  149. this.videoContainer.id + "')\">" +
  150. (this.showMoreValue? "Show less" : "Show More") + "</div><br />";
  151. if(this.showMoreValue)
  152. {
  153. var downloadBandwidth, uploadBandwidth, transport;
  154. if(this.bandwidth === null)
  155. {
  156. downloadBandwidth = "N/A";
  157. uploadBandwidth = "N/A";
  158. }
  159. else
  160. {
  161. downloadBandwidth = this.bandwidth.download?
  162. this.bandwidth.download + " Kbps" :
  163. "N/A";
  164. uploadBandwidth = this.bandwidth.upload?
  165. this.bandwidth.upload + " Kbps" :
  166. "N/A";
  167. }
  168. if(!this.transport || this.transport.length === 0)
  169. {
  170. transport = "<tr>" +
  171. "<td><span class='jitsipopover_blue'>Address:</span></td>" +
  172. "<td> N/A</td></tr>";
  173. }
  174. else
  175. {
  176. var data = {remoteIP: [], localIP:[], remotePort:[], localPort:[]};
  177. for(i = 0; i < this.transport.length; i++)
  178. {
  179. var ip = ConnectionIndicator.getIP(this.transport[i].ip);
  180. var port = ConnectionIndicator.getPort(this.transport[i].ip);
  181. var localIP =
  182. ConnectionIndicator.getIP(this.transport[i].localip);
  183. var localPort =
  184. ConnectionIndicator.getPort(this.transport[i].localip);
  185. if(data.remoteIP.indexOf(ip) == -1)
  186. {
  187. data.remoteIP.push(ip);
  188. }
  189. if(data.remotePort.indexOf(port) == -1)
  190. {
  191. data.remotePort.push(port);
  192. }
  193. if(data.localIP.indexOf(localIP) == -1)
  194. {
  195. data.localIP.push(localIP);
  196. }
  197. if(data.localPort.indexOf(localPort) == -1)
  198. {
  199. data.localPort.push(localPort);
  200. }
  201. }
  202. var localTransport =
  203. "<tr><td><span class='jitsipopover_blue'>Local address" +
  204. (data.localIP.length > 1? "es" : "") + ": </span></td><td> " +
  205. ConnectionIndicator.getStringFromArray(data.localIP) +
  206. "</td></tr>";
  207. transport =
  208. "<tr><td><span class='jitsipopover_blue'>Remote address"+
  209. (data.remoteIP.length > 1? "es" : "") + ":</span></td><td> " +
  210. ConnectionIndicator.getStringFromArray(data.remoteIP) +
  211. "</td></tr>";
  212. if(this.transport.length > 1)
  213. {
  214. transport += "<tr>" +
  215. "<td>" +
  216. "<span class='jitsipopover_blue'>Remote ports:</span>" +
  217. "</td><td>";
  218. localTransport += "<tr>" +
  219. "<td>" +
  220. "<span class='jitsipopover_blue'>Local ports:</span>" +
  221. "</td><td>";
  222. }
  223. else
  224. {
  225. transport +=
  226. "<tr>" +
  227. "<td>" +
  228. "<span class='jitsipopover_blue'>Remote port:</span>" +
  229. "</td><td>";
  230. localTransport +=
  231. "<tr>" +
  232. "<td>" +
  233. "<span class='jitsipopover_blue'>Local port:</span>" +
  234. "</td><td>";
  235. }
  236. transport +=
  237. ConnectionIndicator.getStringFromArray(data.remotePort);
  238. localTransport +=
  239. ConnectionIndicator.getStringFromArray(data.localPort);
  240. transport += "</td></tr>";
  241. transport += localTransport + "</td></tr>";
  242. transport +="<tr>" +
  243. "<td><span class='jitsipopover_blue'>Transport:</span></td>" +
  244. "<td>" + this.transport[0].type + "</td></tr>";
  245. }
  246. result += "<table style='width:100%'>" +
  247. "<tr>" +
  248. "<td>" +
  249. "<span class='jitsipopover_blue'>Estimated bandwidth:</span>" +
  250. "</td><td>" +
  251. "<span class='jitsipopover_green'>&darr;</span>" +
  252. downloadBandwidth +
  253. " <span class='jitsipopover_orange'>&uarr;</span>" +
  254. uploadBandwidth + "</td></tr>";
  255. result += transport + "</table>";
  256. }
  257. return result;
  258. };
  259. /**
  260. * Shows or hide the additional information.
  261. */
  262. ConnectionIndicator.prototype.showMore = function () {
  263. this.showMoreValue = !this.showMoreValue;
  264. this.updatePopoverData();
  265. };
  266. function createIcon(classes)
  267. {
  268. var icon = document.createElement("span");
  269. for(var i in classes)
  270. {
  271. icon.classList.add(classes[i]);
  272. }
  273. icon.appendChild(
  274. document.createElement("i")).classList.add("icon-connection");
  275. return icon;
  276. }
  277. /**
  278. * Creates the indicator
  279. */
  280. ConnectionIndicator.prototype.create = function () {
  281. this.connectionIndicatorContainer = document.createElement("div");
  282. this.connectionIndicatorContainer.className = "connectionindicator";
  283. this.connectionIndicatorContainer.style.display = "none";
  284. this.videoContainer.appendChild(this.connectionIndicatorContainer);
  285. this.popover = new JitsiPopover(
  286. $("#" + this.videoContainer.id + " > .connectionindicator"),
  287. {content: "<div class=\"connection_info\">Come back here for " +
  288. "connection information once the conference starts</div>",
  289. skin: "black"});
  290. this.emptyIcon = this.connectionIndicatorContainer.appendChild(
  291. createIcon(["connection", "connection_empty"]));
  292. this.fullIcon = this.connectionIndicatorContainer.appendChild(
  293. createIcon(["connection", "connection_full"]));
  294. };
  295. /**
  296. * Removes the indicator
  297. */
  298. ConnectionIndicator.prototype.remove = function()
  299. {
  300. this.connectionIndicatorContainer.remove();
  301. this.popover.forceHide();
  302. };
  303. /**
  304. * Updates the data of the indicator
  305. * @param percent the percent of connection quality
  306. * @param object the statistics data.
  307. */
  308. ConnectionIndicator.prototype.updateConnectionQuality =
  309. function (percent, object) {
  310. if(percent === null)
  311. {
  312. this.connectionIndicatorContainer.style.display = "none";
  313. this.popover.forceHide();
  314. return;
  315. }
  316. else
  317. {
  318. if(this.connectionIndicatorContainer.style.display == "none") {
  319. this.connectionIndicatorContainer.style.display = "block";
  320. this.videoLayout.updateMutePosition(this.videoContainer.id);
  321. }
  322. }
  323. this.bandwidth = object.bandwidth;
  324. this.bitrate = object.bitrate;
  325. this.packetLoss = object.packetLoss;
  326. this.transport = object.transport;
  327. if(object.resolution)
  328. {
  329. this.resolution = object.resolution;
  330. }
  331. for(var quality in ConnectionIndicator.connectionQualityValues)
  332. {
  333. if(percent >= quality)
  334. {
  335. this.fullIcon.style.width =
  336. ConnectionIndicator.connectionQualityValues[quality];
  337. }
  338. }
  339. this.updatePopoverData();
  340. };
  341. /**
  342. * Updates the resolution
  343. * @param resolution the new resolution
  344. */
  345. ConnectionIndicator.prototype.updateResolution = function (resolution) {
  346. this.resolution = resolution;
  347. this.updatePopoverData();
  348. };
  349. /**
  350. * Updates the content of the popover
  351. */
  352. ConnectionIndicator.prototype.updatePopoverData = function () {
  353. this.popover.updateContent(
  354. "<div class=\"connection_info\">" + this.generateText() + "</div>");
  355. };
  356. /**
  357. * Hides the popover
  358. */
  359. ConnectionIndicator.prototype.hide = function () {
  360. this.popover.forceHide();
  361. };
  362. /**
  363. * Hides the indicator
  364. */
  365. ConnectionIndicator.prototype.hideIndicator = function () {
  366. this.connectionIndicatorContainer.style.display = "none";
  367. if(this.popover)
  368. this.popover.forceHide();
  369. };
  370. module.exports = ConnectionIndicator;