@webex/plugin-meetings 2.60.1-next.13 → 2.60.1-next.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/interpretation/index.js +1 -1
  4. package/dist/interpretation/siLanguage.js +1 -1
  5. package/dist/mediaQualityMetrics/config.d.ts +103 -99
  6. package/dist/mediaQualityMetrics/config.js +133 -129
  7. package/dist/mediaQualityMetrics/config.js.map +1 -1
  8. package/dist/meeting/index.js +4 -2
  9. package/dist/meeting/index.js.map +1 -1
  10. package/dist/meeting/request.d.ts +2 -0
  11. package/dist/meeting/request.js +4 -0
  12. package/dist/meeting/request.js.map +1 -1
  13. package/dist/meetings/index.js +19 -0
  14. package/dist/meetings/index.js.map +1 -1
  15. package/dist/meetings/util.js +1 -1
  16. package/dist/meetings/util.js.map +1 -1
  17. package/dist/metrics/constants.d.ts +2 -0
  18. package/dist/metrics/constants.js +3 -1
  19. package/dist/metrics/constants.js.map +1 -1
  20. package/dist/reachability/index.js +14 -20
  21. package/dist/reachability/index.js.map +1 -1
  22. package/dist/reconnection-manager/index.js +63 -43
  23. package/dist/reconnection-manager/index.js.map +1 -1
  24. package/dist/roap/turnDiscovery.d.ts +18 -2
  25. package/dist/roap/turnDiscovery.js +163 -69
  26. package/dist/roap/turnDiscovery.js.map +1 -1
  27. package/dist/rtcMetrics/index.d.ts +7 -0
  28. package/dist/rtcMetrics/index.js +38 -1
  29. package/dist/rtcMetrics/index.js.map +1 -1
  30. package/dist/statsAnalyzer/index.js +135 -23
  31. package/dist/statsAnalyzer/index.js.map +1 -1
  32. package/dist/statsAnalyzer/mqaUtil.d.ts +28 -4
  33. package/dist/statsAnalyzer/mqaUtil.js +278 -148
  34. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  35. package/dist/webinar/index.js +1 -1
  36. package/package.json +21 -21
  37. package/src/mediaQualityMetrics/config.ts +107 -107
  38. package/src/meeting/index.ts +2 -0
  39. package/src/meeting/request.ts +6 -0
  40. package/src/meetings/index.ts +22 -0
  41. package/src/meetings/util.ts +1 -1
  42. package/src/metrics/constants.ts +2 -0
  43. package/src/reachability/index.ts +0 -6
  44. package/src/reconnection-manager/index.ts +18 -7
  45. package/src/roap/turnDiscovery.ts +100 -24
  46. package/src/rtcMetrics/index.ts +43 -1
  47. package/src/statsAnalyzer/index.ts +158 -24
  48. package/src/statsAnalyzer/mqaUtil.ts +302 -154
  49. package/test/unit/spec/meeting/index.js +46 -0
  50. package/test/unit/spec/meeting/request.js +2 -0
  51. package/test/unit/spec/meetings/utils.js +35 -8
  52. package/test/unit/spec/reachability/index.ts +74 -0
  53. package/test/unit/spec/reconnection-manager/index.js +36 -1
  54. package/test/unit/spec/roap/turnDiscovery.ts +326 -76
  55. package/test/unit/spec/rtcMetrics/index.ts +32 -3
  56. package/test/unit/spec/stats-analyzer/index.js +439 -1
  57. package/test/utils/webex-test-users.js +12 -4
@@ -27,11 +27,20 @@ export default class TurnDiscovery {
27
27
  * handles TURN_DISCOVERY_RESPONSE roap message
28
28
  *
29
29
  * @param {Object} roapMessage
30
+ * @param {string} from string to indicate how we got the response (used just for logging)
30
31
  * @returns {void}
31
32
  * @public
32
33
  * @memberof Roap
33
34
  */
34
- handleTurnDiscoveryResponse(roapMessage: object): void;
35
+ handleTurnDiscoveryResponse(roapMessage: any, from: string): void;
36
+ /**
37
+ * handles TURN_DISCOVERY_RESPONSE roap message that came in http response
38
+ *
39
+ * @param {Object} roapMessage
40
+ * @returns {Promise}
41
+ * @memberof Roap
42
+ */
43
+ private handleTurnDiscoveryResponseInHttpResponse;
35
44
  /**
36
45
  * sends the TURN_DISCOVERY_REQUEST roap request
37
46
  *
@@ -41,7 +50,7 @@ export default class TurnDiscovery {
41
50
  * @private
42
51
  * @memberof Roap
43
52
  */
44
- sendRoapTurnDiscoveryRequest(meeting: Meeting, isReconnecting: boolean): Promise<void>;
53
+ sendRoapTurnDiscoveryRequest(meeting: Meeting, isReconnecting: boolean): Promise<any>;
45
54
  /**
46
55
  * Sends the OK message that server expects to receive
47
56
  * after it sends us TURN_DISCOVERY_RESPONSE
@@ -87,6 +96,13 @@ export default class TurnDiscovery {
87
96
  */
88
97
  doTurnDiscovery(meeting: Meeting, isReconnecting?: boolean, isForced?: boolean): Promise<{
89
98
  turnServerInfo: any;
99
+ turnDiscoverySkippedReason: string;
100
+ } | {
101
+ turnServerInfo: {
102
+ url: string;
103
+ username: string;
104
+ password: string;
105
+ };
90
106
  turnDiscoverySkippedReason: any;
91
107
  }>;
92
108
  }
@@ -81,20 +81,23 @@ var TurnDiscovery = exports.default = /*#__PURE__*/function () {
81
81
  * handles TURN_DISCOVERY_RESPONSE roap message
82
82
  *
83
83
  * @param {Object} roapMessage
84
+ * @param {string} from string to indicate how we got the response (used just for logging)
84
85
  * @returns {void}
85
86
  * @public
86
87
  * @memberof Roap
87
88
  */
88
89
  }, {
89
90
  key: "handleTurnDiscoveryResponse",
90
- value: function handleTurnDiscoveryResponse(roapMessage) {
91
+ value: function handleTurnDiscoveryResponse(roapMessage, from) {
91
92
  var _this = this;
92
- // @ts-ignore - Fix missing type
93
93
  var headers = roapMessage.headers;
94
94
  if (!this.defer) {
95
- _loggerProxy.default.logger.warn('Roap:turnDiscovery#handleTurnDiscoveryResponse --> unexpected TURN discovery response');
95
+ _loggerProxy.default.logger.warn("Roap:turnDiscovery#handleTurnDiscoveryResponse --> unexpected TURN discovery response ".concat(from));
96
96
  return;
97
97
  }
98
+ if (roapMessage.messageType !== _constants2.ROAP.ROAP_TYPES.TURN_DISCOVERY_RESPONSE) {
99
+ this.defer.reject(new Error("TURN_DISCOVERY_RESPONSE ".concat(from, " has unexpected messageType: ").concat((0, _stringify.default)(roapMessage))));
100
+ }
98
101
  var expectedHeaders = [{
99
102
  headerName: 'x-cisco-turn-url',
100
103
  field: 'url'
@@ -118,14 +121,43 @@ var TurnDiscovery = exports.default = /*#__PURE__*/function () {
118
121
  clearTimeout(this.responseTimer);
119
122
  this.responseTimer = undefined;
120
123
  if (foundHeaders !== expectedHeaders.length) {
121
- _loggerProxy.default.logger.warn("Roap:turnDiscovery#handleTurnDiscoveryResponse --> missing some headers, received: ".concat((0, _stringify.default)(headers)));
122
- this.defer.reject(new Error("TURN_DISCOVERY_RESPONSE missing some headers: ".concat((0, _stringify.default)(headers))));
124
+ _loggerProxy.default.logger.warn("Roap:turnDiscovery#handleTurnDiscoveryResponse --> missing some headers, received ".concat(from, ": ").concat((0, _stringify.default)(headers)));
125
+ this.defer.reject(new Error("TURN_DISCOVERY_RESPONSE ".concat(from, " missing some headers: ").concat((0, _stringify.default)(headers))));
123
126
  } else {
124
- _loggerProxy.default.logger.info("Roap:turnDiscovery#handleTurnDiscoveryResponse --> received a valid response, url=".concat(this.turnInfo.url));
125
- this.defer.resolve();
127
+ _loggerProxy.default.logger.info("Roap:turnDiscovery#handleTurnDiscoveryResponse --> received a valid response ".concat(from, ", url=").concat(this.turnInfo.url));
128
+ this.defer.resolve({
129
+ isOkRequired: !(headers !== null && headers !== void 0 && headers.includes('noOkInTransaction'))
130
+ });
126
131
  }
127
132
  }
128
133
 
134
+ /**
135
+ * handles TURN_DISCOVERY_RESPONSE roap message that came in http response
136
+ *
137
+ * @param {Object} roapMessage
138
+ * @returns {Promise}
139
+ * @memberof Roap
140
+ */
141
+ }, {
142
+ key: "handleTurnDiscoveryResponseInHttpResponse",
143
+ value: (function () {
144
+ var _handleTurnDiscoveryResponseInHttpResponse = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(roapMessage) {
145
+ return _regenerator.default.wrap(function _callee$(_context) {
146
+ while (1) switch (_context.prev = _context.next) {
147
+ case 0:
148
+ this.handleTurnDiscoveryResponse(roapMessage, 'in http response');
149
+ return _context.abrupt("return", this.defer.promise);
150
+ case 2:
151
+ case "end":
152
+ return _context.stop();
153
+ }
154
+ }, _callee, this);
155
+ }));
156
+ function handleTurnDiscoveryResponseInHttpResponse(_x) {
157
+ return _handleTurnDiscoveryResponseInHttpResponse.apply(this, arguments);
158
+ }
159
+ return handleTurnDiscoveryResponseInHttpResponse;
160
+ }()
129
161
  /**
130
162
  * sends the TURN_DISCOVERY_REQUEST roap request
131
163
  *
@@ -135,6 +167,7 @@ var TurnDiscovery = exports.default = /*#__PURE__*/function () {
135
167
  * @private
136
168
  * @memberof Roap
137
169
  */
170
+ )
138
171
  }, {
139
172
  key: "sendRoapTurnDiscoveryRequest",
140
173
  value: function sendRoapTurnDiscoveryRequest(meeting, isReconnecting) {
@@ -146,7 +179,8 @@ var TurnDiscovery = exports.default = /*#__PURE__*/function () {
146
179
  var roapMessage = {
147
180
  messageType: _constants2.ROAP.ROAP_TYPES.TURN_DISCOVERY_REQUEST,
148
181
  version: _constants2.ROAP.ROAP_VERSION,
149
- seq: TURN_DISCOVERY_SEQ
182
+ seq: TURN_DISCOVERY_SEQ,
183
+ headers: ['includeAnswerInHttpResponse', 'noOkInTransaction']
150
184
  };
151
185
  _loggerProxy.default.logger.info('Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> sending TURN_DISCOVERY_REQUEST');
152
186
  return this.roapRequest.sendRoap({
@@ -159,11 +193,40 @@ var TurnDiscovery = exports.default = /*#__PURE__*/function () {
159
193
  locusMediaRequest: meeting.locusMediaRequest,
160
194
  // @ts-ignore - because of meeting.webex
161
195
  ipVersion: _util.default.getIpVersion(meeting.webex)
162
- }).then(function (_ref) {
163
- var mediaConnections = _ref.mediaConnections;
196
+ }).then(function (response) {
197
+ var mediaConnections = response.mediaConnections;
198
+ var turnDiscoveryResponse;
164
199
  if (mediaConnections) {
200
+ var _mediaConnections$;
165
201
  meeting.updateMediaConnections(mediaConnections);
202
+ if ((_mediaConnections$ = mediaConnections[0]) !== null && _mediaConnections$ !== void 0 && _mediaConnections$.remoteSdp) {
203
+ var remoteSdp = JSON.parse(mediaConnections[0].remoteSdp);
204
+ if (remoteSdp.roapMessage) {
205
+ // yes, it's misleading that remoteSdp actually contains a TURN discovery response, but that's how the backend works...
206
+ var _remoteSdp$roapMessag = remoteSdp.roapMessage,
207
+ seq = _remoteSdp$roapMessag.seq,
208
+ messageType = _remoteSdp$roapMessag.messageType,
209
+ errorType = _remoteSdp$roapMessag.errorType,
210
+ errorCause = _remoteSdp$roapMessag.errorCause,
211
+ headers = _remoteSdp$roapMessag.headers;
212
+ turnDiscoveryResponse = {
213
+ seq: seq,
214
+ messageType: messageType,
215
+ errorType: errorType,
216
+ errorCause: errorCause,
217
+ headers: headers
218
+ };
219
+ }
220
+ }
221
+ }
222
+ if (!turnDiscoveryResponse) {
223
+ _metrics.default.sendBehavioralMetric(_constants.default.ROAP_HTTP_RESPONSE_MISSING, {
224
+ correlationId: meeting.correlationId,
225
+ messageType: 'TURN_DISCOVERY_RESPONSE',
226
+ isMultistream: meeting.isMultistream
227
+ });
166
228
  }
229
+ return turnDiscoveryResponse;
167
230
  });
168
231
  }
169
232
 
@@ -202,30 +265,30 @@ var TurnDiscovery = exports.default = /*#__PURE__*/function () {
202
265
  }, {
203
266
  key: "getSkipReason",
204
267
  value: (function () {
205
- var _getSkipReason = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(meeting) {
268
+ var _getSkipReason = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(meeting) {
206
269
  var isAnyPublicClusterReachable;
207
- return _regenerator.default.wrap(function _callee$(_context) {
208
- while (1) switch (_context.prev = _context.next) {
270
+ return _regenerator.default.wrap(function _callee2$(_context2) {
271
+ while (1) switch (_context2.prev = _context2.next) {
209
272
  case 0:
210
- _context.next = 2;
273
+ _context2.next = 2;
211
274
  return meeting.webex.meetings.reachability.isAnyPublicClusterReachable();
212
275
  case 2:
213
- isAnyPublicClusterReachable = _context.sent;
276
+ isAnyPublicClusterReachable = _context2.sent;
214
277
  if (!isAnyPublicClusterReachable) {
215
- _context.next = 6;
278
+ _context2.next = 6;
216
279
  break;
217
280
  }
218
281
  _loggerProxy.default.logger.info('Roap:turnDiscovery#getSkipReason --> reachability has not failed, skipping TURN discovery');
219
- return _context.abrupt("return", 'reachability');
282
+ return _context2.abrupt("return", 'reachability');
220
283
  case 6:
221
- return _context.abrupt("return", '');
284
+ return _context2.abrupt("return", '');
222
285
  case 7:
223
286
  case "end":
224
- return _context.stop();
287
+ return _context2.stop();
225
288
  }
226
- }, _callee);
289
+ }, _callee2);
227
290
  }));
228
- function getSkipReason(_x) {
291
+ function getSkipReason(_x2) {
229
292
  return _getSkipReason.apply(this, arguments);
230
293
  }
231
294
  return getSkipReason;
@@ -240,23 +303,23 @@ var TurnDiscovery = exports.default = /*#__PURE__*/function () {
240
303
  }, {
241
304
  key: "isSkipped",
242
305
  value: (function () {
243
- var _isSkipped = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(meeting) {
306
+ var _isSkipped = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(meeting) {
244
307
  var skipReason;
245
- return _regenerator.default.wrap(function _callee2$(_context2) {
246
- while (1) switch (_context2.prev = _context2.next) {
308
+ return _regenerator.default.wrap(function _callee3$(_context3) {
309
+ while (1) switch (_context3.prev = _context3.next) {
247
310
  case 0:
248
- _context2.next = 2;
311
+ _context3.next = 2;
249
312
  return this.getSkipReason(meeting);
250
313
  case 2:
251
- skipReason = _context2.sent;
252
- return _context2.abrupt("return", !!skipReason);
314
+ skipReason = _context3.sent;
315
+ return _context3.abrupt("return", !!skipReason);
253
316
  case 4:
254
317
  case "end":
255
- return _context2.stop();
318
+ return _context3.stop();
256
319
  }
257
- }, _callee2, this);
320
+ }, _callee3, this);
258
321
  }));
259
- function isSkipped(_x2) {
322
+ function isSkipped(_x3) {
260
323
  return _isSkipped.apply(this, arguments);
261
324
  }
262
325
  return isSkipped;
@@ -283,62 +346,93 @@ var TurnDiscovery = exports.default = /*#__PURE__*/function () {
283
346
  }, {
284
347
  key: "doTurnDiscovery",
285
348
  value: (function () {
286
- var _doTurnDiscovery = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(meeting, isReconnecting, isForced) {
287
- var _this2 = this;
288
- var turnDiscoverySkippedReason;
289
- return _regenerator.default.wrap(function _callee3$(_context3) {
290
- while (1) switch (_context3.prev = _context3.next) {
349
+ var _doTurnDiscovery = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(meeting, isReconnecting, isForced) {
350
+ var turnDiscoverySkippedReason, httpResponse, _ref, isOkRequired;
351
+ return _regenerator.default.wrap(function _callee4$(_context4) {
352
+ while (1) switch (_context4.prev = _context4.next) {
291
353
  case 0:
292
354
  if (isForced) {
293
- _context3.next = 4;
355
+ _context4.next = 4;
294
356
  break;
295
357
  }
296
- _context3.next = 3;
358
+ _context4.next = 3;
297
359
  return this.getSkipReason(meeting);
298
360
  case 3:
299
- turnDiscoverySkippedReason = _context3.sent;
361
+ turnDiscoverySkippedReason = _context4.sent;
300
362
  case 4:
301
363
  if (!turnDiscoverySkippedReason) {
302
- _context3.next = 6;
364
+ _context4.next = 6;
303
365
  break;
304
366
  }
305
- return _context3.abrupt("return", {
367
+ return _context4.abrupt("return", {
306
368
  turnServerInfo: undefined,
307
369
  turnDiscoverySkippedReason: turnDiscoverySkippedReason
308
370
  });
309
371
  case 6:
310
- return _context3.abrupt("return", this.sendRoapTurnDiscoveryRequest(meeting, isReconnecting).then(function () {
311
- return _this2.waitForTurnDiscoveryResponse();
312
- }).then(function () {
313
- return _this2.sendRoapOK(meeting);
314
- }).then(function () {
315
- _this2.defer = undefined;
316
- _loggerProxy.default.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery completed');
317
- return {
318
- turnServerInfo: _this2.turnInfo,
319
- turnDiscoverySkippedReason: undefined
320
- };
321
- }).catch(function (e) {
322
- // we catch any errors and resolve with no turn information so that the normal call join flow can continue without TURN
323
- _loggerProxy.default.logger.info("Roap:turnDiscovery#doTurnDiscovery --> TURN discovery failed, continuing without TURN: ".concat(e));
324
- _metrics.default.sendBehavioralMetric(_constants.default.TURN_DISCOVERY_FAILURE, {
325
- correlation_id: meeting.correlationId,
326
- locus_id: meeting.locusUrl.split('/').pop(),
327
- reason: e.message,
328
- stack: e.stack
329
- });
330
- return {
331
- turnServerInfo: undefined,
332
- turnDiscoverySkippedReason: undefined
333
- };
334
- }));
335
- case 7:
372
+ _context4.prev = 6;
373
+ _context4.next = 9;
374
+ return this.sendRoapTurnDiscoveryRequest(meeting, isReconnecting);
375
+ case 9:
376
+ httpResponse = _context4.sent;
377
+ if (!httpResponse) {
378
+ _context4.next = 16;
379
+ break;
380
+ }
381
+ _context4.next = 13;
382
+ return this.handleTurnDiscoveryResponseInHttpResponse(httpResponse);
383
+ case 13:
384
+ _context4.t0 = _context4.sent;
385
+ _context4.next = 19;
386
+ break;
387
+ case 16:
388
+ _context4.next = 18;
389
+ return this.waitForTurnDiscoveryResponse();
390
+ case 18:
391
+ _context4.t0 = _context4.sent;
392
+ case 19:
393
+ _ref = _context4.t0;
394
+ isOkRequired = _ref.isOkRequired;
395
+ if (!isOkRequired) {
396
+ _context4.next = 26;
397
+ break;
398
+ }
399
+ _context4.next = 24;
400
+ return this.sendRoapOK(meeting);
401
+ case 24:
402
+ _loggerProxy.default.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery response requires OK');
403
+ _metrics.default.sendBehavioralMetric(_constants.default.TURN_DISCOVERY_REQUIRES_OK, {
404
+ correlation_id: meeting.correlationId,
405
+ locus_id: meeting.locusUrl.split('/').pop()
406
+ });
407
+ case 26:
408
+ this.defer = undefined;
409
+ _loggerProxy.default.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery completed');
410
+ return _context4.abrupt("return", {
411
+ turnServerInfo: this.turnInfo,
412
+ turnDiscoverySkippedReason: undefined
413
+ });
414
+ case 31:
415
+ _context4.prev = 31;
416
+ _context4.t1 = _context4["catch"](6);
417
+ // we catch any errors and resolve with no turn information so that the normal call join flow can continue without TURN
418
+ _loggerProxy.default.logger.info("Roap:turnDiscovery#doTurnDiscovery --> TURN discovery failed, continuing without TURN: ".concat(_context4.t1));
419
+ _metrics.default.sendBehavioralMetric(_constants.default.TURN_DISCOVERY_FAILURE, {
420
+ correlation_id: meeting.correlationId,
421
+ locus_id: meeting.locusUrl.split('/').pop(),
422
+ reason: _context4.t1.message,
423
+ stack: _context4.t1.stack
424
+ });
425
+ return _context4.abrupt("return", {
426
+ turnServerInfo: undefined,
427
+ turnDiscoverySkippedReason: undefined
428
+ });
429
+ case 36:
336
430
  case "end":
337
- return _context3.stop();
431
+ return _context4.stop();
338
432
  }
339
- }, _callee3, this);
433
+ }, _callee4, this, [[6, 31]]);
340
434
  }));
341
- function doTurnDiscovery(_x3, _x4, _x5) {
435
+ function doTurnDiscovery(_x4, _x5, _x6) {
342
436
  return _doTurnDiscovery.apply(this, arguments);
343
437
  }
344
438
  return doTurnDiscovery;
@@ -1 +1 @@
1
- {"version":3,"names":["_common","require","_metrics","_interopRequireDefault","_constants","_loggerProxy","_constants2","_util","TURN_DISCOVERY_TIMEOUT","TURN_DISCOVERY_SEQ","TurnDiscovery","exports","default","roapRequest","_classCallCheck2","_defineProperty2","turnInfo","url","username","password","_createClass2","key","value","waitForTurnDiscoveryResponse","defer","LoggerProxy","logger","warn","_promise","reject","Error","responseTimer","setTimeout","concat","info","promise","handleTurnDiscoveryResponse","roapMessage","_this","headers","expectedHeaders","headerName","field","foundHeaders","forEach","receivedHeader","expectedHeader","startsWith","substring","length","clearTimeout","undefined","_stringify","resolve","sendRoapTurnDiscoveryRequest","meeting","isReconnecting","Defer","messageType","ROAP","ROAP_TYPES","TURN_DISCOVERY_REQUEST","version","ROAP_VERSION","seq","sendRoap","locusSelfUrl","selfUrl","mediaId","meetingId","id","locusMediaRequest","ipVersion","MeetingUtil","getIpVersion","webex","then","_ref","mediaConnections","updateMediaConnections","sendRoapOK","OK","_getSkipReason","_asyncToGenerator2","_regenerator","mark","_callee","isAnyPublicClusterReachable","wrap","_callee$","_context","prev","next","meetings","reachability","sent","abrupt","stop","getSkipReason","_x","apply","arguments","_isSkipped","_callee2","skipReason","_callee2$","_context2","isSkipped","_x2","_doTurnDiscovery","_callee3","isForced","_this2","turnDiscoverySkippedReason","_callee3$","_context3","turnServerInfo","catch","e","Metrics","sendBehavioralMetric","BEHAVIORAL_METRICS","TURN_DISCOVERY_FAILURE","correlation_id","correlationId","locus_id","locusUrl","split","pop","reason","message","stack","doTurnDiscovery","_x3","_x4","_x5"],"sources":["turnDiscovery.ts"],"sourcesContent":["// @ts-ignore - Types not available for @webex/common\nimport {Defer} from '@webex/common';\n\nimport Metrics from '../metrics';\nimport BEHAVIORAL_METRICS from '../metrics/constants';\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport {ROAP} from '../constants';\n\nimport RoapRequest from './request';\nimport Meeting from '../meeting';\nimport MeetingUtil from '../meeting/util';\n\nconst TURN_DISCOVERY_TIMEOUT = 10; // in seconds\n\n// Roap spec says that seq should start from 1, but TURN discovery works fine with seq=0\n// and this is handy for us, because TURN discovery is always done before the first SDP exchange,\n// so we can do it with seq=0 or not do it at all and then we create the RoapMediaConnection\n// and do the SDP offer with seq=1\nconst TURN_DISCOVERY_SEQ = 0;\n\n/**\n * Handles the process of finding out TURN server information from Linus.\n * This is achieved by sending a TURN_DISCOVERY_REQUEST.\n */\nexport default class TurnDiscovery {\n private roapRequest: RoapRequest;\n\n private defer?: Defer; // used for waiting for the response\n\n private turnInfo: {\n url: string;\n username: string;\n password: string;\n };\n\n private responseTimer?: ReturnType<typeof setTimeout>;\n\n /**\n * Constructor\n *\n * @param {RoapRequest} roapRequest\n */\n constructor(roapRequest: RoapRequest) {\n this.roapRequest = roapRequest;\n this.turnInfo = {\n url: '',\n username: '',\n password: '',\n };\n }\n\n /**\n * waits for TURN_DISCOVERY_RESPONSE message to arrive\n *\n * @returns {Promise}\n * @private\n * @memberof Roap\n */\n private waitForTurnDiscoveryResponse() {\n if (!this.defer) {\n LoggerProxy.logger.warn(\n 'Roap:turnDiscovery#waitForTurnDiscoveryResponse --> TURN discovery is not in progress'\n );\n\n return Promise.reject(\n new Error('waitForTurnDiscoveryResponse() called before sendRoapTurnDiscoveryRequest()')\n );\n }\n\n const {defer} = this;\n\n this.responseTimer = setTimeout(() => {\n LoggerProxy.logger.warn(\n `Roap:turnDiscovery#waitForTurnDiscoveryResponse --> timeout! no response arrived within ${TURN_DISCOVERY_TIMEOUT} seconds`\n );\n\n defer.reject(new Error('Timed out waiting for TURN_DISCOVERY_RESPONSE'));\n }, TURN_DISCOVERY_TIMEOUT * 1000);\n\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#waitForTurnDiscoveryResponse --> waiting for TURN_DISCOVERY_RESPONSE...'\n );\n\n return defer.promise;\n }\n\n /**\n * handles TURN_DISCOVERY_RESPONSE roap message\n *\n * @param {Object} roapMessage\n * @returns {void}\n * @public\n * @memberof Roap\n */\n public handleTurnDiscoveryResponse(roapMessage: object) {\n // @ts-ignore - Fix missing type\n const {headers} = roapMessage;\n\n if (!this.defer) {\n LoggerProxy.logger.warn(\n 'Roap:turnDiscovery#handleTurnDiscoveryResponse --> unexpected TURN discovery response'\n );\n\n return;\n }\n\n const expectedHeaders = [\n {headerName: 'x-cisco-turn-url', field: 'url'},\n {headerName: 'x-cisco-turn-username', field: 'username'},\n {headerName: 'x-cisco-turn-password', field: 'password'},\n ];\n\n let foundHeaders = 0;\n\n headers?.forEach((receivedHeader) => {\n // check if it matches any of our expected headers\n expectedHeaders.forEach((expectedHeader) => {\n if (receivedHeader.startsWith(`${expectedHeader.headerName}=`)) {\n this.turnInfo[expectedHeader.field] = receivedHeader.substring(\n expectedHeader.headerName.length + 1\n );\n foundHeaders += 1;\n }\n });\n });\n\n clearTimeout(this.responseTimer);\n this.responseTimer = undefined;\n\n if (foundHeaders !== expectedHeaders.length) {\n LoggerProxy.logger.warn(\n `Roap:turnDiscovery#handleTurnDiscoveryResponse --> missing some headers, received: ${JSON.stringify(\n headers\n )}`\n );\n this.defer.reject(\n new Error(`TURN_DISCOVERY_RESPONSE missing some headers: ${JSON.stringify(headers)}`)\n );\n } else {\n LoggerProxy.logger.info(\n `Roap:turnDiscovery#handleTurnDiscoveryResponse --> received a valid response, url=${this.turnInfo.url}`\n );\n this.defer.resolve();\n }\n }\n\n /**\n * sends the TURN_DISCOVERY_REQUEST roap request\n *\n * @param {Meeting} meeting\n * @param {Boolean} isReconnecting\n * @returns {Promise}\n * @private\n * @memberof Roap\n */\n sendRoapTurnDiscoveryRequest(meeting: Meeting, isReconnecting: boolean) {\n if (this.defer) {\n LoggerProxy.logger.warn(\n 'Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> already in progress'\n );\n\n return Promise.resolve();\n }\n\n this.defer = new Defer();\n\n const roapMessage = {\n messageType: ROAP.ROAP_TYPES.TURN_DISCOVERY_REQUEST,\n version: ROAP.ROAP_VERSION,\n seq: TURN_DISCOVERY_SEQ,\n };\n\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> sending TURN_DISCOVERY_REQUEST'\n );\n\n return this.roapRequest\n .sendRoap({\n roapMessage,\n // @ts-ignore - Fix missing type\n locusSelfUrl: meeting.selfUrl,\n // @ts-ignore - Fix missing type\n mediaId: isReconnecting ? '' : meeting.mediaId,\n meetingId: meeting.id,\n locusMediaRequest: meeting.locusMediaRequest,\n // @ts-ignore - because of meeting.webex\n ipVersion: MeetingUtil.getIpVersion(meeting.webex),\n })\n .then(({mediaConnections}) => {\n if (mediaConnections) {\n meeting.updateMediaConnections(mediaConnections);\n }\n });\n }\n\n /**\n * Sends the OK message that server expects to receive\n * after it sends us TURN_DISCOVERY_RESPONSE\n *\n * @param {Meeting} meeting\n * @returns {Promise}\n */\n sendRoapOK(meeting: Meeting) {\n LoggerProxy.logger.info('Roap:turnDiscovery#sendRoapOK --> sending OK');\n\n return this.roapRequest.sendRoap({\n roapMessage: {\n messageType: ROAP.ROAP_TYPES.OK,\n version: ROAP.ROAP_VERSION,\n seq: TURN_DISCOVERY_SEQ,\n },\n // @ts-ignore - fix type\n locusSelfUrl: meeting.selfUrl,\n // @ts-ignore - fix type\n mediaId: meeting.mediaId,\n meetingId: meeting.id,\n locusMediaRequest: meeting.locusMediaRequest,\n });\n }\n\n /**\n * Gets the reason why reachability is skipped.\n *\n * @param {Meeting} meeting\n * @returns {Promise<string>} Promise with empty string if reachability is not skipped or a reason if it is skipped\n */\n private async getSkipReason(meeting: Meeting): Promise<string> {\n const isAnyPublicClusterReachable =\n // @ts-ignore - fix type\n await meeting.webex.meetings.reachability.isAnyPublicClusterReachable();\n\n if (isAnyPublicClusterReachable) {\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#getSkipReason --> reachability has not failed, skipping TURN discovery'\n );\n\n return 'reachability';\n }\n\n return '';\n }\n\n /**\n * Checks if TURN discovery is skipped.\n *\n * @param {Meeting} meeting\n * @returns {Boolean} true if TURN discovery is being skipped, false if it is being done\n */\n async isSkipped(meeting) {\n const skipReason = await this.getSkipReason(meeting);\n\n return !!skipReason;\n }\n\n /**\n * Retrieves TURN server information from the backend by doing\n * a roap message exchange:\n * client server\n * | -----TURN_DISCOVERY_REQUEST-----> |\n * | <----TURN_DISCOVERY_RESPONSE----- |\n * | --------------OK----------------> |\n *\n * This TURN discovery roap exchange is always done with seq=0.\n * The RoapMediaConnection SDP exchange always starts with seq=1,\n * so it works fine no matter if TURN discovery is done or not.\n *\n * @param {Meeting} meeting\n * @param {Boolean} [isReconnecting] should be set to true if this is a new\n * media connection just after a reconnection\n * @param {Boolean} [isForced]\n * @returns {Promise}\n */\n async doTurnDiscovery(meeting: Meeting, isReconnecting?: boolean, isForced?: boolean) {\n let turnDiscoverySkippedReason: string;\n\n if (!isForced) {\n turnDiscoverySkippedReason = await this.getSkipReason(meeting);\n }\n\n if (turnDiscoverySkippedReason) {\n return {\n turnServerInfo: undefined,\n turnDiscoverySkippedReason,\n };\n }\n\n return this.sendRoapTurnDiscoveryRequest(meeting, isReconnecting)\n .then(() => this.waitForTurnDiscoveryResponse())\n .then(() => this.sendRoapOK(meeting))\n .then(() => {\n this.defer = undefined;\n\n LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery completed');\n\n return {turnServerInfo: this.turnInfo, turnDiscoverySkippedReason: undefined};\n })\n .catch((e) => {\n // we catch any errors and resolve with no turn information so that the normal call join flow can continue without TURN\n LoggerProxy.logger.info(\n `Roap:turnDiscovery#doTurnDiscovery --> TURN discovery failed, continuing without TURN: ${e}`\n );\n\n Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.TURN_DISCOVERY_FAILURE, {\n correlation_id: meeting.correlationId,\n locus_id: meeting.locusUrl.split('/').pop(),\n reason: e.message,\n stack: e.stack,\n });\n\n return {turnServerInfo: undefined, turnDiscoverySkippedReason: undefined};\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"names":["_common","require","_metrics","_interopRequireDefault","_constants","_loggerProxy","_constants2","_util","TURN_DISCOVERY_TIMEOUT","TURN_DISCOVERY_SEQ","TurnDiscovery","exports","default","roapRequest","_classCallCheck2","_defineProperty2","turnInfo","url","username","password","_createClass2","key","value","waitForTurnDiscoveryResponse","defer","LoggerProxy","logger","warn","_promise","reject","Error","responseTimer","setTimeout","concat","info","promise","handleTurnDiscoveryResponse","roapMessage","from","_this","headers","messageType","ROAP","ROAP_TYPES","TURN_DISCOVERY_RESPONSE","_stringify","expectedHeaders","headerName","field","foundHeaders","forEach","receivedHeader","expectedHeader","startsWith","substring","length","clearTimeout","undefined","resolve","isOkRequired","includes","_handleTurnDiscoveryResponseInHttpResponse","_asyncToGenerator2","_regenerator","mark","_callee","wrap","_callee$","_context","prev","next","abrupt","stop","handleTurnDiscoveryResponseInHttpResponse","_x","apply","arguments","sendRoapTurnDiscoveryRequest","meeting","isReconnecting","Defer","TURN_DISCOVERY_REQUEST","version","ROAP_VERSION","seq","sendRoap","locusSelfUrl","selfUrl","mediaId","meetingId","id","locusMediaRequest","ipVersion","MeetingUtil","getIpVersion","webex","then","response","mediaConnections","turnDiscoveryResponse","_mediaConnections$","updateMediaConnections","remoteSdp","JSON","parse","_remoteSdp$roapMessag","errorType","errorCause","Metrics","sendBehavioralMetric","BEHAVIORAL_METRICS","ROAP_HTTP_RESPONSE_MISSING","correlationId","isMultistream","sendRoapOK","OK","_getSkipReason","_callee2","isAnyPublicClusterReachable","_callee2$","_context2","meetings","reachability","sent","getSkipReason","_x2","_isSkipped","_callee3","skipReason","_callee3$","_context3","isSkipped","_x3","_doTurnDiscovery","_callee4","isForced","turnDiscoverySkippedReason","httpResponse","_ref","_callee4$","_context4","turnServerInfo","t0","TURN_DISCOVERY_REQUIRES_OK","correlation_id","locus_id","locusUrl","split","pop","t1","TURN_DISCOVERY_FAILURE","reason","message","stack","doTurnDiscovery","_x4","_x5","_x6"],"sources":["turnDiscovery.ts"],"sourcesContent":["// @ts-ignore - Types not available for @webex/common\nimport {Defer} from '@webex/common';\n\nimport Metrics from '../metrics';\nimport BEHAVIORAL_METRICS from '../metrics/constants';\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport {ROAP} from '../constants';\n\nimport RoapRequest from './request';\nimport Meeting from '../meeting';\nimport MeetingUtil from '../meeting/util';\n\nconst TURN_DISCOVERY_TIMEOUT = 10; // in seconds\n\n// Roap spec says that seq should start from 1, but TURN discovery works fine with seq=0\n// and this is handy for us, because TURN discovery is always done before the first SDP exchange,\n// so we can do it with seq=0 or not do it at all and then we create the RoapMediaConnection\n// and do the SDP offer with seq=1\nconst TURN_DISCOVERY_SEQ = 0;\n\n/**\n * Handles the process of finding out TURN server information from Linus.\n * This is achieved by sending a TURN_DISCOVERY_REQUEST.\n */\nexport default class TurnDiscovery {\n private roapRequest: RoapRequest;\n\n private defer?: Defer; // used for waiting for the response\n\n private turnInfo: {\n url: string;\n username: string;\n password: string;\n };\n\n private responseTimer?: ReturnType<typeof setTimeout>;\n\n /**\n * Constructor\n *\n * @param {RoapRequest} roapRequest\n */\n constructor(roapRequest: RoapRequest) {\n this.roapRequest = roapRequest;\n this.turnInfo = {\n url: '',\n username: '',\n password: '',\n };\n }\n\n /**\n * waits for TURN_DISCOVERY_RESPONSE message to arrive\n *\n * @returns {Promise}\n * @private\n * @memberof Roap\n */\n private waitForTurnDiscoveryResponse(): Promise<{isOkRequired: boolean}> {\n if (!this.defer) {\n LoggerProxy.logger.warn(\n 'Roap:turnDiscovery#waitForTurnDiscoveryResponse --> TURN discovery is not in progress'\n );\n\n return Promise.reject(\n new Error('waitForTurnDiscoveryResponse() called before sendRoapTurnDiscoveryRequest()')\n );\n }\n\n const {defer} = this;\n\n this.responseTimer = setTimeout(() => {\n LoggerProxy.logger.warn(\n `Roap:turnDiscovery#waitForTurnDiscoveryResponse --> timeout! no response arrived within ${TURN_DISCOVERY_TIMEOUT} seconds`\n );\n\n defer.reject(new Error('Timed out waiting for TURN_DISCOVERY_RESPONSE'));\n }, TURN_DISCOVERY_TIMEOUT * 1000);\n\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#waitForTurnDiscoveryResponse --> waiting for TURN_DISCOVERY_RESPONSE...'\n );\n\n return defer.promise;\n }\n\n /**\n * handles TURN_DISCOVERY_RESPONSE roap message\n *\n * @param {Object} roapMessage\n * @param {string} from string to indicate how we got the response (used just for logging)\n * @returns {void}\n * @public\n * @memberof Roap\n */\n public handleTurnDiscoveryResponse(roapMessage: any, from: string) {\n const {headers} = roapMessage;\n\n if (!this.defer) {\n LoggerProxy.logger.warn(\n `Roap:turnDiscovery#handleTurnDiscoveryResponse --> unexpected TURN discovery response ${from}`\n );\n\n return;\n }\n\n if (roapMessage.messageType !== ROAP.ROAP_TYPES.TURN_DISCOVERY_RESPONSE) {\n this.defer.reject(\n new Error(\n `TURN_DISCOVERY_RESPONSE ${from} has unexpected messageType: ${JSON.stringify(\n roapMessage\n )}`\n )\n );\n }\n\n const expectedHeaders = [\n {headerName: 'x-cisco-turn-url', field: 'url'},\n {headerName: 'x-cisco-turn-username', field: 'username'},\n {headerName: 'x-cisco-turn-password', field: 'password'},\n ];\n\n let foundHeaders = 0;\n\n headers?.forEach((receivedHeader) => {\n // check if it matches any of our expected headers\n expectedHeaders.forEach((expectedHeader) => {\n if (receivedHeader.startsWith(`${expectedHeader.headerName}=`)) {\n this.turnInfo[expectedHeader.field] = receivedHeader.substring(\n expectedHeader.headerName.length + 1\n );\n foundHeaders += 1;\n }\n });\n });\n\n clearTimeout(this.responseTimer);\n this.responseTimer = undefined;\n\n if (foundHeaders !== expectedHeaders.length) {\n LoggerProxy.logger.warn(\n `Roap:turnDiscovery#handleTurnDiscoveryResponse --> missing some headers, received ${from}: ${JSON.stringify(\n headers\n )}`\n );\n this.defer.reject(\n new Error(\n `TURN_DISCOVERY_RESPONSE ${from} missing some headers: ${JSON.stringify(headers)}`\n )\n );\n } else {\n LoggerProxy.logger.info(\n `Roap:turnDiscovery#handleTurnDiscoveryResponse --> received a valid response ${from}, url=${this.turnInfo.url}`\n );\n\n this.defer.resolve({isOkRequired: !headers?.includes('noOkInTransaction')});\n }\n }\n\n /**\n * handles TURN_DISCOVERY_RESPONSE roap message that came in http response\n *\n * @param {Object} roapMessage\n * @returns {Promise}\n * @memberof Roap\n */\n private async handleTurnDiscoveryResponseInHttpResponse(\n roapMessage: object\n ): Promise<{isOkRequired: boolean}> {\n this.handleTurnDiscoveryResponse(roapMessage, 'in http response');\n\n return this.defer.promise;\n }\n\n /**\n * sends the TURN_DISCOVERY_REQUEST roap request\n *\n * @param {Meeting} meeting\n * @param {Boolean} isReconnecting\n * @returns {Promise}\n * @private\n * @memberof Roap\n */\n sendRoapTurnDiscoveryRequest(meeting: Meeting, isReconnecting: boolean) {\n if (this.defer) {\n LoggerProxy.logger.warn(\n 'Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> already in progress'\n );\n\n return Promise.resolve();\n }\n\n this.defer = new Defer();\n\n const roapMessage = {\n messageType: ROAP.ROAP_TYPES.TURN_DISCOVERY_REQUEST,\n version: ROAP.ROAP_VERSION,\n seq: TURN_DISCOVERY_SEQ,\n headers: ['includeAnswerInHttpResponse', 'noOkInTransaction'],\n };\n\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> sending TURN_DISCOVERY_REQUEST'\n );\n\n return this.roapRequest\n .sendRoap({\n roapMessage,\n // @ts-ignore - Fix missing type\n locusSelfUrl: meeting.selfUrl,\n // @ts-ignore - Fix missing type\n mediaId: isReconnecting ? '' : meeting.mediaId,\n meetingId: meeting.id,\n locusMediaRequest: meeting.locusMediaRequest,\n // @ts-ignore - because of meeting.webex\n ipVersion: MeetingUtil.getIpVersion(meeting.webex),\n })\n .then((response) => {\n const {mediaConnections} = response;\n\n let turnDiscoveryResponse;\n\n if (mediaConnections) {\n meeting.updateMediaConnections(mediaConnections);\n\n if (mediaConnections[0]?.remoteSdp) {\n const remoteSdp = JSON.parse(mediaConnections[0].remoteSdp);\n\n if (remoteSdp.roapMessage) {\n // yes, it's misleading that remoteSdp actually contains a TURN discovery response, but that's how the backend works...\n const {seq, messageType, errorType, errorCause, headers} = remoteSdp.roapMessage;\n\n turnDiscoveryResponse = {\n seq,\n messageType,\n errorType,\n errorCause,\n headers,\n };\n }\n }\n }\n\n if (!turnDiscoveryResponse) {\n Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ROAP_HTTP_RESPONSE_MISSING, {\n correlationId: meeting.correlationId,\n messageType: 'TURN_DISCOVERY_RESPONSE',\n isMultistream: meeting.isMultistream,\n });\n }\n\n return turnDiscoveryResponse;\n });\n }\n\n /**\n * Sends the OK message that server expects to receive\n * after it sends us TURN_DISCOVERY_RESPONSE\n *\n * @param {Meeting} meeting\n * @returns {Promise}\n */\n sendRoapOK(meeting: Meeting) {\n LoggerProxy.logger.info('Roap:turnDiscovery#sendRoapOK --> sending OK');\n\n return this.roapRequest.sendRoap({\n roapMessage: {\n messageType: ROAP.ROAP_TYPES.OK,\n version: ROAP.ROAP_VERSION,\n seq: TURN_DISCOVERY_SEQ,\n },\n // @ts-ignore - fix type\n locusSelfUrl: meeting.selfUrl,\n // @ts-ignore - fix type\n mediaId: meeting.mediaId,\n meetingId: meeting.id,\n locusMediaRequest: meeting.locusMediaRequest,\n });\n }\n\n /**\n * Gets the reason why reachability is skipped.\n *\n * @param {Meeting} meeting\n * @returns {Promise<string>} Promise with empty string if reachability is not skipped or a reason if it is skipped\n */\n private async getSkipReason(meeting: Meeting): Promise<string> {\n const isAnyPublicClusterReachable =\n // @ts-ignore - fix type\n await meeting.webex.meetings.reachability.isAnyPublicClusterReachable();\n\n if (isAnyPublicClusterReachable) {\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#getSkipReason --> reachability has not failed, skipping TURN discovery'\n );\n\n return 'reachability';\n }\n\n return '';\n }\n\n /**\n * Checks if TURN discovery is skipped.\n *\n * @param {Meeting} meeting\n * @returns {Boolean} true if TURN discovery is being skipped, false if it is being done\n */\n async isSkipped(meeting) {\n const skipReason = await this.getSkipReason(meeting);\n\n return !!skipReason;\n }\n\n /**\n * Retrieves TURN server information from the backend by doing\n * a roap message exchange:\n * client server\n * | -----TURN_DISCOVERY_REQUEST-----> |\n * | <----TURN_DISCOVERY_RESPONSE----- |\n * | --------------OK----------------> |\n *\n * This TURN discovery roap exchange is always done with seq=0.\n * The RoapMediaConnection SDP exchange always starts with seq=1,\n * so it works fine no matter if TURN discovery is done or not.\n *\n * @param {Meeting} meeting\n * @param {Boolean} [isReconnecting] should be set to true if this is a new\n * media connection just after a reconnection\n * @param {Boolean} [isForced]\n * @returns {Promise}\n */\n async doTurnDiscovery(meeting: Meeting, isReconnecting?: boolean, isForced?: boolean) {\n let turnDiscoverySkippedReason: string;\n\n if (!isForced) {\n turnDiscoverySkippedReason = await this.getSkipReason(meeting);\n }\n\n if (turnDiscoverySkippedReason) {\n return {\n turnServerInfo: undefined,\n turnDiscoverySkippedReason,\n };\n }\n\n try {\n const httpResponse = await this.sendRoapTurnDiscoveryRequest(meeting, isReconnecting);\n\n // if we haven't got the response over http, we need to wait for it to come over the websocket via Mercury\n const {isOkRequired} = httpResponse\n ? await this.handleTurnDiscoveryResponseInHttpResponse(httpResponse)\n : await this.waitForTurnDiscoveryResponse();\n\n if (isOkRequired) {\n await this.sendRoapOK(meeting);\n\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#doTurnDiscovery --> TURN discovery response requires OK'\n );\n\n Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.TURN_DISCOVERY_REQUIRES_OK, {\n correlation_id: meeting.correlationId,\n locus_id: meeting.locusUrl.split('/').pop(),\n });\n }\n\n this.defer = undefined;\n\n LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery completed');\n\n return {turnServerInfo: this.turnInfo, turnDiscoverySkippedReason: undefined};\n } catch (e) {\n // we catch any errors and resolve with no turn information so that the normal call join flow can continue without TURN\n LoggerProxy.logger.info(\n `Roap:turnDiscovery#doTurnDiscovery --> TURN discovery failed, continuing without TURN: ${e}`\n );\n\n Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.TURN_DISCOVERY_FAILURE, {\n correlation_id: meeting.correlationId,\n locus_id: meeting.locusUrl.split('/').pop(),\n reason: e.message,\n stack: e.stack,\n });\n\n return {turnServerInfo: undefined, turnDiscoverySkippedReason: undefined};\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AACA,IAAAA,OAAA,GAAAC,OAAA;AAEA,IAAAC,QAAA,GAAAC,sBAAA,CAAAF,OAAA;AACA,IAAAG,UAAA,GAAAD,sBAAA,CAAAF,OAAA;AACA,IAAAI,YAAA,GAAAF,sBAAA,CAAAF,OAAA;AACA,IAAAK,WAAA,GAAAL,OAAA;AAIA,IAAAM,KAAA,GAAAJ,sBAAA,CAAAF,OAAA;AAVA;;AAYA,IAAMO,sBAAsB,GAAG,EAAE,CAAC,CAAC;;AAEnC;AACA;AACA;AACA;AACA,IAAMC,kBAAkB,GAAG,CAAC;;AAE5B;AACA;AACA;AACA;AAHA,IAIqBC,aAAa,GAAAC,OAAA,CAAAC,OAAA;EAahC;AACF;AACA;AACA;AACA;EACE,SAAAF,cAAYG,WAAwB,EAAE;IAAA,IAAAC,gBAAA,CAAAF,OAAA,QAAAF,aAAA;IAAA,IAAAK,gBAAA,CAAAH,OAAA;IAAA,IAAAG,gBAAA,CAAAH,OAAA;IAff;IAAA,IAAAG,gBAAA,CAAAH,OAAA;IAAA,IAAAG,gBAAA,CAAAH,OAAA;IAgBrB,IAAI,CAACC,WAAW,GAAGA,WAAW;IAC9B,IAAI,CAACG,QAAQ,GAAG;MACdC,GAAG,EAAE,EAAE;MACPC,QAAQ,EAAE,EAAE;MACZC,QAAQ,EAAE;IACZ,CAAC;EACH;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;EANE,IAAAC,aAAA,CAAAR,OAAA,EAAAF,aAAA;IAAAW,GAAA;IAAAC,KAAA,EAOA,SAAAC,6BAAA,EAAyE;MACvE,IAAI,CAAC,IAAI,CAACC,KAAK,EAAE;QACfC,oBAAW,CAACC,MAAM,CAACC,IAAI,CACrB,uFACF,CAAC;QAED,OAAOC,QAAA,CAAAhB,OAAA,CAAQiB,MAAM,CACnB,IAAIC,KAAK,CAAC,6EAA6E,CACzF,CAAC;MACH;MAEA,IAAON,KAAK,GAAI,IAAI,CAAbA,KAAK;MAEZ,IAAI,CAACO,aAAa,GAAGC,UAAU,CAAC,YAAM;QACpCP,oBAAW,CAACC,MAAM,CAACC,IAAI,4FAAAM,MAAA,CACsEzB,sBAAsB,aACnH,CAAC;QAEDgB,KAAK,CAACK,MAAM,CAAC,IAAIC,KAAK,CAAC,+CAA+C,CAAC,CAAC;MAC1E,CAAC,EAAEtB,sBAAsB,GAAG,IAAI,CAAC;MAEjCiB,oBAAW,CAACC,MAAM,CAACQ,IAAI,CACrB,4FACF,CAAC;MAED,OAAOV,KAAK,CAACW,OAAO;IACtB;;IAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EARE;IAAAd,GAAA;IAAAC,KAAA,EASA,SAAAc,4BAAmCC,WAAgB,EAAEC,IAAY,EAAE;MAAA,IAAAC,KAAA;MACjE,IAAOC,OAAO,GAAIH,WAAW,CAAtBG,OAAO;MAEd,IAAI,CAAC,IAAI,CAAChB,KAAK,EAAE;QACfC,oBAAW,CAACC,MAAM,CAACC,IAAI,0FAAAM,MAAA,CACoEK,IAAI,CAC/F,CAAC;QAED;MACF;MAEA,IAAID,WAAW,CAACI,WAAW,KAAKC,gBAAI,CAACC,UAAU,CAACC,uBAAuB,EAAE;QACvE,IAAI,CAACpB,KAAK,CAACK,MAAM,CACf,IAAIC,KAAK,4BAAAG,MAAA,CACoBK,IAAI,mCAAAL,MAAA,CAAgC,IAAAY,UAAA,CAAAjC,OAAA,EAC7DyB,WACF,CAAC,CACH,CACF,CAAC;MACH;MAEA,IAAMS,eAAe,GAAG,CACtB;QAACC,UAAU,EAAE,kBAAkB;QAAEC,KAAK,EAAE;MAAK,CAAC,EAC9C;QAACD,UAAU,EAAE,uBAAuB;QAAEC,KAAK,EAAE;MAAU,CAAC,EACxD;QAACD,UAAU,EAAE,uBAAuB;QAAEC,KAAK,EAAE;MAAU,CAAC,CACzD;MAED,IAAIC,YAAY,GAAG,CAAC;MAEpBT,OAAO,aAAPA,OAAO,uBAAPA,OAAO,CAAEU,OAAO,CAAC,UAACC,cAAc,EAAK;QACnC;QACAL,eAAe,CAACI,OAAO,CAAC,UAACE,cAAc,EAAK;UAC1C,IAAID,cAAc,CAACE,UAAU,IAAApB,MAAA,CAAImB,cAAc,CAACL,UAAU,MAAG,CAAC,EAAE;YAC9DR,KAAI,CAACvB,QAAQ,CAACoC,cAAc,CAACJ,KAAK,CAAC,GAAGG,cAAc,CAACG,SAAS,CAC5DF,cAAc,CAACL,UAAU,CAACQ,MAAM,GAAG,CACrC,CAAC;YACDN,YAAY,IAAI,CAAC;UACnB;QACF,CAAC,CAAC;MACJ,CAAC,CAAC;MAEFO,YAAY,CAAC,IAAI,CAACzB,aAAa,CAAC;MAChC,IAAI,CAACA,aAAa,GAAG0B,SAAS;MAE9B,IAAIR,YAAY,KAAKH,eAAe,CAACS,MAAM,EAAE;QAC3C9B,oBAAW,CAACC,MAAM,CAACC,IAAI,sFAAAM,MAAA,CACgEK,IAAI,QAAAL,MAAA,CAAK,IAAAY,UAAA,CAAAjC,OAAA,EAC5F4B,OACF,CAAC,CACH,CAAC;QACD,IAAI,CAAChB,KAAK,CAACK,MAAM,CACf,IAAIC,KAAK,4BAAAG,MAAA,CACoBK,IAAI,6BAAAL,MAAA,CAA0B,IAAAY,UAAA,CAAAjC,OAAA,EAAe4B,OAAO,CAAC,CAClF,CACF,CAAC;MACH,CAAC,MAAM;QACLf,oBAAW,CAACC,MAAM,CAACQ,IAAI,iFAAAD,MAAA,CAC2DK,IAAI,YAAAL,MAAA,CAAS,IAAI,CAACjB,QAAQ,CAACC,GAAG,CAChH,CAAC;QAED,IAAI,CAACO,KAAK,CAACkC,OAAO,CAAC;UAACC,YAAY,EAAE,EAACnB,OAAO,aAAPA,OAAO,eAAPA,OAAO,CAAEoB,QAAQ,CAAC,mBAAmB,CAAC;QAAA,CAAC,CAAC;MAC7E;IACF;;IAEA;AACF;AACA;AACA;AACA;AACA;AACA;EANE;IAAAvC,GAAA;IAAAC,KAAA;MAAA,IAAAuC,0CAAA,OAAAC,kBAAA,CAAAlD,OAAA,gBAAAmD,YAAA,CAAAnD,OAAA,CAAAoD,IAAA,CAOA,SAAAC,QACE5B,WAAmB;QAAA,OAAA0B,YAAA,CAAAnD,OAAA,CAAAsD,IAAA,UAAAC,SAAAC,QAAA;UAAA,kBAAAA,QAAA,CAAAC,IAAA,GAAAD,QAAA,CAAAE,IAAA;YAAA;cAEnB,IAAI,CAAClC,2BAA2B,CAACC,WAAW,EAAE,kBAAkB,CAAC;cAAC,OAAA+B,QAAA,CAAAG,MAAA,WAE3D,IAAI,CAAC/C,KAAK,CAACW,OAAO;YAAA;YAAA;cAAA,OAAAiC,QAAA,CAAAI,IAAA;UAAA;QAAA,GAAAP,OAAA;MAAA,CAC1B;MAAA,SAAAQ,0CAAAC,EAAA;QAAA,OAAAb,0CAAA,CAAAc,KAAA,OAAAC,SAAA;MAAA;MAAA,OAAAH,yCAAA;IAAA;IAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;IARE;EAAA;IAAApD,GAAA;IAAAC,KAAA,EASA,SAAAuD,6BAA6BC,OAAgB,EAAEC,cAAuB,EAAE;MACtE,IAAI,IAAI,CAACvD,KAAK,EAAE;QACdC,oBAAW,CAACC,MAAM,CAACC,IAAI,CACrB,yEACF,CAAC;QAED,OAAOC,QAAA,CAAAhB,OAAA,CAAQ8C,OAAO,CAAC,CAAC;MAC1B;MAEA,IAAI,CAAClC,KAAK,GAAG,IAAIwD,aAAK,CAAC,CAAC;MAExB,IAAM3C,WAAW,GAAG;QAClBI,WAAW,EAAEC,gBAAI,CAACC,UAAU,CAACsC,sBAAsB;QACnDC,OAAO,EAAExC,gBAAI,CAACyC,YAAY;QAC1BC,GAAG,EAAE3E,kBAAkB;QACvB+B,OAAO,EAAE,CAAC,6BAA6B,EAAE,mBAAmB;MAC9D,CAAC;MAEDf,oBAAW,CAACC,MAAM,CAACQ,IAAI,CACrB,oFACF,CAAC;MAED,OAAO,IAAI,CAACrB,WAAW,CACpBwE,QAAQ,CAAC;QACRhD,WAAW,EAAXA,WAAW;QACX;QACAiD,YAAY,EAAER,OAAO,CAACS,OAAO;QAC7B;QACAC,OAAO,EAAET,cAAc,GAAG,EAAE,GAAGD,OAAO,CAACU,OAAO;QAC9CC,SAAS,EAAEX,OAAO,CAACY,EAAE;QACrBC,iBAAiB,EAAEb,OAAO,CAACa,iBAAiB;QAC5C;QACAC,SAAS,EAAEC,aAAW,CAACC,YAAY,CAAChB,OAAO,CAACiB,KAAK;MACnD,CAAC,CAAC,CACDC,IAAI,CAAC,UAACC,QAAQ,EAAK;QAClB,IAAOC,gBAAgB,GAAID,QAAQ,CAA5BC,gBAAgB;QAEvB,IAAIC,qBAAqB;QAEzB,IAAID,gBAAgB,EAAE;UAAA,IAAAE,kBAAA;UACpBtB,OAAO,CAACuB,sBAAsB,CAACH,gBAAgB,CAAC;UAEhD,KAAAE,kBAAA,GAAIF,gBAAgB,CAAC,CAAC,CAAC,cAAAE,kBAAA,eAAnBA,kBAAA,CAAqBE,SAAS,EAAE;YAClC,IAAMA,SAAS,GAAGC,IAAI,CAACC,KAAK,CAACN,gBAAgB,CAAC,CAAC,CAAC,CAACI,SAAS,CAAC;YAE3D,IAAIA,SAAS,CAACjE,WAAW,EAAE;cACzB;cACA,IAAAoE,qBAAA,GAA2DH,SAAS,CAACjE,WAAW;gBAAzE+C,GAAG,GAAAqB,qBAAA,CAAHrB,GAAG;gBAAE3C,WAAW,GAAAgE,qBAAA,CAAXhE,WAAW;gBAAEiE,SAAS,GAAAD,qBAAA,CAATC,SAAS;gBAAEC,UAAU,GAAAF,qBAAA,CAAVE,UAAU;gBAAEnE,OAAO,GAAAiE,qBAAA,CAAPjE,OAAO;cAEvD2D,qBAAqB,GAAG;gBACtBf,GAAG,EAAHA,GAAG;gBACH3C,WAAW,EAAXA,WAAW;gBACXiE,SAAS,EAATA,SAAS;gBACTC,UAAU,EAAVA,UAAU;gBACVnE,OAAO,EAAPA;cACF,CAAC;YACH;UACF;QACF;QAEA,IAAI,CAAC2D,qBAAqB,EAAE;UAC1BS,gBAAO,CAACC,oBAAoB,CAACC,kBAAkB,CAACC,0BAA0B,EAAE;YAC1EC,aAAa,EAAElC,OAAO,CAACkC,aAAa;YACpCvE,WAAW,EAAE,yBAAyB;YACtCwE,aAAa,EAAEnC,OAAO,CAACmC;UACzB,CAAC,CAAC;QACJ;QAEA,OAAOd,qBAAqB;MAC9B,CAAC,CAAC;IACN;;IAEA;AACF;AACA;AACA;AACA;AACA;AACA;EANE;IAAA9E,GAAA;IAAAC,KAAA,EAOA,SAAA4F,WAAWpC,OAAgB,EAAE;MAC3BrD,oBAAW,CAACC,MAAM,CAACQ,IAAI,CAAC,8CAA8C,CAAC;MAEvE,OAAO,IAAI,CAACrB,WAAW,CAACwE,QAAQ,CAAC;QAC/BhD,WAAW,EAAE;UACXI,WAAW,EAAEC,gBAAI,CAACC,UAAU,CAACwE,EAAE;UAC/BjC,OAAO,EAAExC,gBAAI,CAACyC,YAAY;UAC1BC,GAAG,EAAE3E;QACP,CAAC;QACD;QACA6E,YAAY,EAAER,OAAO,CAACS,OAAO;QAC7B;QACAC,OAAO,EAAEV,OAAO,CAACU,OAAO;QACxBC,SAAS,EAAEX,OAAO,CAACY,EAAE;QACrBC,iBAAiB,EAAEb,OAAO,CAACa;MAC7B,CAAC,CAAC;IACJ;;IAEA;AACF;AACA;AACA;AACA;AACA;EALE;IAAAtE,GAAA;IAAAC,KAAA;MAAA,IAAA8F,cAAA,OAAAtD,kBAAA,CAAAlD,OAAA,gBAAAmD,YAAA,CAAAnD,OAAA,CAAAoD,IAAA,CAMA,SAAAqD,SAA4BvC,OAAgB;QAAA,IAAAwC,2BAAA;QAAA,OAAAvD,YAAA,CAAAnD,OAAA,CAAAsD,IAAA,UAAAqD,UAAAC,SAAA;UAAA,kBAAAA,SAAA,CAAAnD,IAAA,GAAAmD,SAAA,CAAAlD,IAAA;YAAA;cAAAkD,SAAA,CAAAlD,IAAA;cAAA,OAGlCQ,OAAO,CAACiB,KAAK,CAAC0B,QAAQ,CAACC,YAAY,CAACJ,2BAA2B,CAAC,CAAC;YAAA;cAFnEA,2BAA2B,GAAAE,SAAA,CAAAG,IAAA;cAAA,KAI7BL,2BAA2B;gBAAAE,SAAA,CAAAlD,IAAA;gBAAA;cAAA;cAC7B7C,oBAAW,CAACC,MAAM,CAACQ,IAAI,CACrB,2FACF,CAAC;cAAC,OAAAsF,SAAA,CAAAjD,MAAA,WAEK,cAAc;YAAA;cAAA,OAAAiD,SAAA,CAAAjD,MAAA,WAGhB,EAAE;YAAA;YAAA;cAAA,OAAAiD,SAAA,CAAAhD,IAAA;UAAA;QAAA,GAAA6C,QAAA;MAAA,CACV;MAAA,SAAAO,cAAAC,GAAA;QAAA,OAAAT,cAAA,CAAAzC,KAAA,OAAAC,SAAA;MAAA;MAAA,OAAAgD,aAAA;IAAA;IAED;AACF;AACA;AACA;AACA;AACA;IALE;EAAA;IAAAvG,GAAA;IAAAC,KAAA;MAAA,IAAAwG,UAAA,OAAAhE,kBAAA,CAAAlD,OAAA,gBAAAmD,YAAA,CAAAnD,OAAA,CAAAoD,IAAA,CAMA,SAAA+D,SAAgBjD,OAAO;QAAA,IAAAkD,UAAA;QAAA,OAAAjE,YAAA,CAAAnD,OAAA,CAAAsD,IAAA,UAAA+D,UAAAC,SAAA;UAAA,kBAAAA,SAAA,CAAA7D,IAAA,GAAA6D,SAAA,CAAA5D,IAAA;YAAA;cAAA4D,SAAA,CAAA5D,IAAA;cAAA,OACI,IAAI,CAACsD,aAAa,CAAC9C,OAAO,CAAC;YAAA;cAA9CkD,UAAU,GAAAE,SAAA,CAAAP,IAAA;cAAA,OAAAO,SAAA,CAAA3D,MAAA,WAET,CAAC,CAACyD,UAAU;YAAA;YAAA;cAAA,OAAAE,SAAA,CAAA1D,IAAA;UAAA;QAAA,GAAAuD,QAAA;MAAA,CACpB;MAAA,SAAAI,UAAAC,GAAA;QAAA,OAAAN,UAAA,CAAAnD,KAAA,OAAAC,SAAA;MAAA;MAAA,OAAAuD,SAAA;IAAA;IAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;IAjBE;EAAA;IAAA9G,GAAA;IAAAC,KAAA;MAAA,IAAA+G,gBAAA,OAAAvE,kBAAA,CAAAlD,OAAA,gBAAAmD,YAAA,CAAAnD,OAAA,CAAAoD,IAAA,CAkBA,SAAAsE,SAAsBxD,OAAgB,EAAEC,cAAwB,EAAEwD,QAAkB;QAAA,IAAAC,0BAAA,EAAAC,YAAA,EAAAC,IAAA,EAAA/E,YAAA;QAAA,OAAAI,YAAA,CAAAnD,OAAA,CAAAsD,IAAA,UAAAyE,UAAAC,SAAA;UAAA,kBAAAA,SAAA,CAAAvE,IAAA,GAAAuE,SAAA,CAAAtE,IAAA;YAAA;cAAA,IAG7EiE,QAAQ;gBAAAK,SAAA,CAAAtE,IAAA;gBAAA;cAAA;cAAAsE,SAAA,CAAAtE,IAAA;cAAA,OACwB,IAAI,CAACsD,aAAa,CAAC9C,OAAO,CAAC;YAAA;cAA9D0D,0BAA0B,GAAAI,SAAA,CAAAjB,IAAA;YAAA;cAAA,KAGxBa,0BAA0B;gBAAAI,SAAA,CAAAtE,IAAA;gBAAA;cAAA;cAAA,OAAAsE,SAAA,CAAArE,MAAA,WACrB;gBACLsE,cAAc,EAAEpF,SAAS;gBACzB+E,0BAA0B,EAA1BA;cACF,CAAC;YAAA;cAAAI,SAAA,CAAAvE,IAAA;cAAAuE,SAAA,CAAAtE,IAAA;cAAA,OAI0B,IAAI,CAACO,4BAA4B,CAACC,OAAO,EAAEC,cAAc,CAAC;YAAA;cAA/E0D,YAAY,GAAAG,SAAA,CAAAjB,IAAA;cAAA,KAGKc,YAAY;gBAAAG,SAAA,CAAAtE,IAAA;gBAAA;cAAA;cAAAsE,SAAA,CAAAtE,IAAA;cAAA,OACzB,IAAI,CAACG,yCAAyC,CAACgE,YAAY,CAAC;YAAA;cAAAG,SAAA,CAAAE,EAAA,GAAAF,SAAA,CAAAjB,IAAA;cAAAiB,SAAA,CAAAtE,IAAA;cAAA;YAAA;cAAAsE,SAAA,CAAAtE,IAAA;cAAA,OAC5D,IAAI,CAAC/C,4BAA4B,CAAC,CAAC;YAAA;cAAAqH,SAAA,CAAAE,EAAA,GAAAF,SAAA,CAAAjB,IAAA;YAAA;cAAAe,IAAA,GAAAE,SAAA,CAAAE,EAAA;cAFtCnF,YAAY,GAAA+E,IAAA,CAAZ/E,YAAY;cAAA,KAIfA,YAAY;gBAAAiF,SAAA,CAAAtE,IAAA;gBAAA;cAAA;cAAAsE,SAAA,CAAAtE,IAAA;cAAA,OACR,IAAI,CAAC4C,UAAU,CAACpC,OAAO,CAAC;YAAA;cAE9BrD,oBAAW,CAACC,MAAM,CAACQ,IAAI,CACrB,4EACF,CAAC;cAED0E,gBAAO,CAACC,oBAAoB,CAACC,kBAAkB,CAACiC,0BAA0B,EAAE;gBAC1EC,cAAc,EAAElE,OAAO,CAACkC,aAAa;gBACrCiC,QAAQ,EAAEnE,OAAO,CAACoE,QAAQ,CAACC,KAAK,CAAC,GAAG,CAAC,CAACC,GAAG,CAAC;cAC5C,CAAC,CAAC;YAAC;cAGL,IAAI,CAAC5H,KAAK,GAAGiC,SAAS;cAEtBhC,oBAAW,CAACC,MAAM,CAACQ,IAAI,CAAC,iEAAiE,CAAC;cAAC,OAAA0G,SAAA,CAAArE,MAAA,WAEpF;gBAACsE,cAAc,EAAE,IAAI,CAAC7H,QAAQ;gBAAEwH,0BAA0B,EAAE/E;cAAS,CAAC;YAAA;cAAAmF,SAAA,CAAAvE,IAAA;cAAAuE,SAAA,CAAAS,EAAA,GAAAT,SAAA;cAE7E;cACAnH,oBAAW,CAACC,MAAM,CAACQ,IAAI,2FAAAD,MAAA,CAAA2G,SAAA,CAAAS,EAAA,CAEvB,CAAC;cAEDzC,gBAAO,CAACC,oBAAoB,CAACC,kBAAkB,CAACwC,sBAAsB,EAAE;gBACtEN,cAAc,EAAElE,OAAO,CAACkC,aAAa;gBACrCiC,QAAQ,EAAEnE,OAAO,CAACoE,QAAQ,CAACC,KAAK,CAAC,GAAG,CAAC,CAACC,GAAG,CAAC,CAAC;gBAC3CG,MAAM,EAAEX,SAAA,CAAAS,EAAA,CAAEG,OAAO;gBACjBC,KAAK,EAAEb,SAAA,CAAAS,EAAA,CAAEI;cACX,CAAC,CAAC;cAAC,OAAAb,SAAA,CAAArE,MAAA,WAEI;gBAACsE,cAAc,EAAEpF,SAAS;gBAAE+E,0BAA0B,EAAE/E;cAAS,CAAC;YAAA;YAAA;cAAA,OAAAmF,SAAA,CAAApE,IAAA;UAAA;QAAA,GAAA8D,QAAA;MAAA,CAE5E;MAAA,SAAAoB,gBAAAC,GAAA,EAAAC,GAAA,EAAAC,GAAA;QAAA,OAAAxB,gBAAA,CAAA1D,KAAA,OAAAC,SAAA;MAAA;MAAA,OAAA8E,eAAA;IAAA;EAAA;EAAA,OAAAhJ,aAAA;AAAA"}
@@ -10,6 +10,7 @@ export default class RtcMetrics {
10
10
  webex: any;
11
11
  meetingId: string;
12
12
  correlationId: string;
13
+ connectionId: string;
13
14
  /**
14
15
  * Initialize the interval.
15
16
  *
@@ -45,6 +46,12 @@ export default class RtcMetrics {
45
46
  * @returns {string}
46
47
  */
47
48
  anonymizeIp(stats: string): string;
49
+ /**
50
+ * Set a new connection id.
51
+ *
52
+ * @returns {void}
53
+ */
54
+ private setNewConnectionId;
48
55
  /**
49
56
  * Send metrics to the metrics service.
50
57
  *
@@ -11,8 +11,21 @@ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/he
11
11
  var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/createClass"));
12
12
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/defineProperty"));
13
13
  var _internalPluginMetrics = require("@webex/internal-plugin-metrics");
14
+ var _uuid = _interopRequireDefault(require("uuid"));
14
15
  var _constants = _interopRequireDefault(require("./constants"));
15
16
  /* eslint-disable class-methods-use-this */
17
+
18
+ var parseJsonPayload = function parseJsonPayload(payload) {
19
+ try {
20
+ if (payload && payload[0]) {
21
+ return JSON.parse(payload[0]);
22
+ }
23
+ return null;
24
+ } catch (_) {
25
+ return null;
26
+ }
27
+ };
28
+
16
29
  /**
17
30
  * Rtc Metrics
18
31
  */
@@ -34,11 +47,13 @@ var RtcMetrics = exports.default = /*#__PURE__*/function () {
34
47
  (0, _defineProperty2.default)(this, "webex", void 0);
35
48
  (0, _defineProperty2.default)(this, "meetingId", void 0);
36
49
  (0, _defineProperty2.default)(this, "correlationId", void 0);
50
+ (0, _defineProperty2.default)(this, "connectionId", void 0);
37
51
  // `window` is used to prevent typescript from returning a NodeJS.Timer.
38
52
  this.intervalId = window.setInterval(this.sendMetricsInQueue.bind(this), 30 * 1000);
39
53
  this.meetingId = meetingId;
40
54
  this.webex = webex;
41
55
  this.correlationId = correlationId;
56
+ this.setNewConnectionId();
42
57
  // Send the first set of metrics at 5 seconds in the case of a user leaving the call shortly after joining.
43
58
  setTimeout(this.sendMetricsInQueue.bind(this), 5 * 1000);
44
59
  }
@@ -72,6 +87,16 @@ var RtcMetrics = exports.default = /*#__PURE__*/function () {
72
87
  data.payload = data.payload.map(this.anonymizeIp);
73
88
  }
74
89
  this.metricsQueue.push(data);
90
+ try {
91
+ // If a connection fails, send the rest of the metrics in queue and get a new connection id.
92
+ var parsedPayload = parseJsonPayload(data.payload);
93
+ if (data.name === 'onconnectionstatechange' && parsedPayload && parsedPayload.value === 'failed') {
94
+ this.sendMetricsInQueue();
95
+ this.setNewConnectionId();
96
+ }
97
+ } catch (e) {
98
+ console.error(e);
99
+ }
75
100
  }
76
101
  }
77
102
 
@@ -106,6 +131,17 @@ var RtcMetrics = exports.default = /*#__PURE__*/function () {
106
131
  return (0, _stringify.default)(data);
107
132
  }
108
133
 
134
+ /**
135
+ * Set a new connection id.
136
+ *
137
+ * @returns {void}
138
+ */
139
+ }, {
140
+ key: "setNewConnectionId",
141
+ value: function setNewConnectionId() {
142
+ this.connectionId = _uuid.default.v4();
143
+ }
144
+
109
145
  /**
110
146
  * Send metrics to the metrics service.
111
147
  *
@@ -125,10 +161,11 @@ var RtcMetrics = exports.default = /*#__PURE__*/function () {
125
161
  body: {
126
162
  metrics: [{
127
163
  type: 'webrtc',
128
- version: '1.0.1',
164
+ version: '1.1.0',
129
165
  userId: this.webex.internal.device.userId,
130
166
  meetingId: this.meetingId,
131
167
  correlationId: this.correlationId,
168
+ connectionId: this.connectionId,
132
169
  data: this.metricsQueue
133
170
  }]
134
171
  }