You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CallStats.js 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /* global $, Strophe, callstats */
  2. var logger = require("jitsi-meet-logger").getLogger(__filename);
  3. var jsSHA = require('jssha');
  4. var io = require('socket.io-client');
  5. /**
  6. * @const
  7. * @see http://www.callstats.io/api/#enumeration-of-wrtcfuncnames
  8. */
  9. var wrtcFuncNames = {
  10. createOffer: "createOffer",
  11. createAnswer: "createAnswer",
  12. setLocalDescription: "setLocalDescription",
  13. setRemoteDescription: "setRemoteDescription",
  14. addIceCandidate: "addIceCandidate",
  15. getUserMedia: "getUserMedia"
  16. };
  17. var callStats = null;
  18. function initCallback (err, msg) {
  19. logger.log("CallStats Status: err=" + err + " msg=" + msg);
  20. }
  21. /**
  22. * Returns a function which invokes f in a try/catch block, logs any exception
  23. * to the console, and then swallows it.
  24. *
  25. * @param f the function to invoke in a try/catch block
  26. * @return a function which invokes f in a try/catch block, logs any exception
  27. * to the console, and then swallows it
  28. */
  29. function _try_catch (f) {
  30. return function () {
  31. try {
  32. f.apply(this, arguments);
  33. } catch (e) {
  34. logger.error(e);
  35. }
  36. };
  37. }
  38. /**
  39. * Creates new CallStats instance that handles all callstats API calls.
  40. * @param peerConnection {JingleSessionPC} the session object
  41. * @param Settings {Settings} the settings instance. Declared in
  42. * /modules/settings/Settings.js
  43. * @param options {object} credentials for callstats.
  44. */
  45. var CallStats = _try_catch(function(jingleSession, Settings, options) {
  46. try{
  47. //check weather that should work with more than 1 peerconnection
  48. if(!callStats) {
  49. callStats = new callstats($, io, jsSHA);
  50. } else {
  51. return;
  52. }
  53. this.session = jingleSession;
  54. this.peerconnection = jingleSession.peerconnection.peerconnection;
  55. this.userID = Settings.getCallStatsUserName();
  56. //FIXME: change it to something else (maybe roomName)
  57. var location = window.location;
  58. this.confID = location.hostname + location.pathname;
  59. //userID is generated or given by the origin server
  60. callStats.initialize(options.callStatsID,
  61. options.callStatsSecret,
  62. this.userID,
  63. initCallback);
  64. callStats.addNewFabric(this.peerconnection,
  65. Strophe.getResourceFromJid(jingleSession.peerjid),
  66. callStats.fabricUsage.multiplex,
  67. this.confID,
  68. this.pcCallback.bind(this));
  69. } catch (e) {
  70. // The callstats.io API failed to initialize (e.g. because its
  71. // download failed to succeed in general or on time). Further
  72. // attempts to utilize it cannot possibly succeed.
  73. callStats = null;
  74. logger.error(e);
  75. }
  76. // notify callstats about failures if there were any
  77. if (CallStats.pendingErrors.length) {
  78. CallStats.pendingErrors.forEach(function (error) {
  79. CallStats._reportError.call(this, error.type, error.error,
  80. error.pc);
  81. }, this);
  82. CallStats.pendingErrors.length = 0;
  83. }
  84. });
  85. // some errors may happen before CallStats init
  86. // in this case we accumulate them in this array
  87. // and send them to callstats on init
  88. CallStats.pendingErrors = [];
  89. CallStats.prototype.pcCallback = _try_catch(function (err, msg) {
  90. if (!callStats) {
  91. return;
  92. }
  93. logger.log("Monitoring status: "+ err + " msg: " + msg);
  94. callStats.sendFabricEvent(this.peerconnection,
  95. callStats.fabricEvent.fabricSetup, this.confID);
  96. });
  97. /**
  98. * Notifies CallStats for mute events
  99. * @param mute {boolean} true for muted and false for not muted
  100. * @param type {String} "audio"/"video"
  101. */
  102. CallStats.prototype.sendMuteEvent = _try_catch(function (mute, type) {
  103. if (!callStats) {
  104. return;
  105. }
  106. var event = null;
  107. if (type === "video") {
  108. event = (mute? callStats.fabricEvent.videoPause :
  109. callStats.fabricEvent.videoResume);
  110. }
  111. else {
  112. event = (mute? callStats.fabricEvent.audioMute :
  113. callStats.fabricEvent.audioUnmute);
  114. }
  115. callStats.sendFabricEvent(this.peerconnection, event, this.confID);
  116. });
  117. /**
  118. * Notifies CallStats for connection setup errors
  119. */
  120. CallStats.prototype.sendTerminateEvent = _try_catch(function () {
  121. if(!callStats) {
  122. return;
  123. }
  124. callStats.sendFabricEvent(this.peerconnection,
  125. callStats.fabricEvent.fabricTerminated, this.confID);
  126. });
  127. /**
  128. * Notifies CallStats for connection setup errors
  129. */
  130. CallStats.prototype.sendSetupFailedEvent = _try_catch(function () {
  131. if(!callStats) {
  132. return;
  133. }
  134. callStats.sendFabricEvent(this.peerconnection,
  135. callStats.fabricEvent.fabricSetupFailed, this.confID);
  136. });
  137. /**
  138. * Sends the given feedback through CallStats.
  139. *
  140. * @param overallFeedback an integer between 1 and 5 indicating the
  141. * user feedback
  142. * @param detailedFeedback detailed feedback from the user. Not yet used
  143. */
  144. CallStats.prototype.sendFeedback = _try_catch(
  145. function(overallFeedback, detailedFeedback) {
  146. if(!callStats) {
  147. return;
  148. }
  149. var feedbackString = '{"userID":"' + this.userID + '"' +
  150. ', "overall":' + overallFeedback +
  151. ', "comment": "' + detailedFeedback + '"}';
  152. var feedbackJSON = JSON.parse(feedbackString);
  153. callStats.sendUserFeedback(this.confID, feedbackJSON);
  154. });
  155. /**
  156. * Reports an error to callstats.
  157. *
  158. * @param type the type of the error, which will be one of the wrtcFuncNames
  159. * @param e the error
  160. * @param pc the peerconnection
  161. * @private
  162. */
  163. CallStats._reportError = function (type, e, pc) {
  164. if (callStats) {
  165. callStats.reportError(pc, this.confID, type, e);
  166. } else {
  167. CallStats.pendingErrors.push({ type: type, error: e, pc: pc});
  168. }
  169. // else just ignore it
  170. };
  171. /**
  172. * Notifies CallStats that getUserMedia failed.
  173. *
  174. * @param {Error} e error to send
  175. * @param {CallStats} cs callstats instance related to the error (optional)
  176. */
  177. CallStats.sendGetUserMediaFailed = _try_catch(function (e, cs) {
  178. CallStats._reportError.call(cs, wrtcFuncNames.getUserMedia, e, null);
  179. });
  180. /**
  181. * Notifies CallStats that peer connection failed to create offer.
  182. *
  183. * @param {Error} e error to send
  184. * @param {RTCPeerConnection} pc connection on which failure occured.
  185. * @param {CallStats} cs callstats instance related to the error (optional)
  186. */
  187. CallStats.sendCreateOfferFailed = _try_catch(function (e, pc, cs) {
  188. CallStats._reportError.call(cs, wrtcFuncNames.createOffer, e, pc);
  189. });
  190. /**
  191. * Notifies CallStats that peer connection failed to create answer.
  192. *
  193. * @param {Error} e error to send
  194. * @param {RTCPeerConnection} pc connection on which failure occured.
  195. * @param {CallStats} cs callstats instance related to the error (optional)
  196. */
  197. CallStats.sendCreateAnswerFailed = _try_catch(function (e, pc, cs) {
  198. CallStats._reportError.call(cs, wrtcFuncNames.createAnswer, e, pc);
  199. });
  200. /**
  201. * Notifies CallStats that peer connection failed to set local description.
  202. *
  203. * @param {Error} e error to send
  204. * @param {RTCPeerConnection} pc connection on which failure occured.
  205. * @param {CallStats} cs callstats instance related to the error (optional)
  206. */
  207. CallStats.sendSetLocalDescFailed = _try_catch(function (e, pc, cs) {
  208. CallStats._reportError.call(cs, wrtcFuncNames.setLocalDescription, e, pc);
  209. });
  210. /**
  211. * Notifies CallStats that peer connection failed to set remote description.
  212. *
  213. * @param {Error} e error to send
  214. * @param {RTCPeerConnection} pc connection on which failure occured.
  215. * @param {CallStats} cs callstats instance related to the error (optional)
  216. */
  217. CallStats.sendSetRemoteDescFailed = _try_catch(function (e, pc, cs) {
  218. CallStats._reportError.call(cs, wrtcFuncNames.setRemoteDescription, e, pc);
  219. });
  220. /**
  221. * Notifies CallStats that peer connection failed to add ICE candidate.
  222. *
  223. * @param {Error} e error to send
  224. * @param {RTCPeerConnection} pc connection on which failure occured.
  225. * @param {CallStats} cs callstats instance related to the error (optional)
  226. */
  227. CallStats.sendAddIceCandidateFailed = _try_catch(function (e, pc, cs) {
  228. CallStats._reportError.call(cs, wrtcFuncNames.addIceCandidate, e, pc);
  229. });
  230. module.exports = CallStats;