@webex/plugin-meetings 2.33.1 → 2.34.0

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.
@@ -240,13 +240,19 @@ var TurnDiscovery = /*#__PURE__*/function () {
240
240
  if (isAnyClusterReachable) {
241
241
  _loggerProxy.default.logger.info('Roap:turnDiscovery#doTurnDiscovery --> reachability has not failed, skipping TURN discovery');
242
242
 
243
- return _promise.default.resolve(undefined);
243
+ return _promise.default.resolve({
244
+ turnServerInfo: undefined,
245
+ turnDiscoverySkippedReason: 'reachability'
246
+ });
244
247
  }
245
248
 
246
249
  if (!meeting.config.experimental.enableTurnDiscovery) {
247
250
  _loggerProxy.default.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery disabled in config, skipping it');
248
251
 
249
- return _promise.default.resolve(undefined);
252
+ return _promise.default.resolve({
253
+ turnServerInfo: undefined,
254
+ turnDiscoverySkippedReason: 'config'
255
+ });
250
256
  }
251
257
 
252
258
  return this.sendRoapTurnDiscoveryRequest(meeting, isReconnecting).then(function () {
@@ -258,7 +264,10 @@ var TurnDiscovery = /*#__PURE__*/function () {
258
264
 
259
265
  _loggerProxy.default.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery completed');
260
266
 
261
- return _this2.turnInfo;
267
+ return {
268
+ turnServerInfo: _this2.turnInfo,
269
+ turnDiscoverySkippedReason: undefined
270
+ };
262
271
  }).catch(function (e) {
263
272
  // we catch any errors and resolve with no turn information so that the normal call join flow can continue without TURN
264
273
  _loggerProxy.default.logger.info("Roap:turnDiscovery#doTurnDiscovery --> TURN discovery failed, continuing without TURN: ".concat(e));
@@ -270,7 +279,10 @@ var TurnDiscovery = /*#__PURE__*/function () {
270
279
  stack: e.stack
271
280
  });
272
281
 
273
- return _promise.default.resolve(undefined);
282
+ return _promise.default.resolve({
283
+ turnServerInfo: undefined,
284
+ turnDiscoverySkippedReason: undefined
285
+ });
274
286
  });
275
287
  }
276
288
  }]);
@@ -1 +1 @@
1
- {"version":3,"names":["TURN_DISCOVERY_TIMEOUT","TurnDiscovery","roapRequest","turnInfo","url","username","password","defer","LoggerProxy","logger","warn","reject","Error","responseTimer","setTimeout","info","promise","roapMessage","headers","expectedHeaders","headerName","field","foundHeaders","forEach","receivedHeader","expectedHeader","startsWith","substring","length","clearTimeout","undefined","resolve","meeting","isReconnecting","seq","roapSeq","Defer","messageType","ROAP","ROAP_TYPES","TURN_DISCOVERY_REQUEST","version","ROAP_VERSION","sendRoap","correlationId","locusSelfUrl","selfUrl","mediaId","audioMuted","isAudioMuted","videoMuted","isVideoMuted","meetingId","id","then","mediaConnections","setRoapSeq","updateMediaConnections","OK","isAnyClusterReachable","webex","meetings","reachability","config","experimental","enableTurnDiscovery","sendRoapTurnDiscoveryRequest","waitForTurnDiscoveryResponse","sendRoapOK","catch","e","Metrics","sendBehavioralMetric","BEHAVIORAL_METRICS","TURN_DISCOVERY_FAILURE","correlation_id","locus_id","locusUrl","split","pop","reason","message","stack"],"sources":["turnDiscovery.ts"],"sourcesContent":["import {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';\n\nconst TURN_DISCOVERY_TIMEOUT = 10; // in seconds\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 /**\n * waits for TURN_DISCOVERY_RESPONSE message to arrive\n *\n * @returns {Promise}\n * @private\n * @memberof Roap\n */\n waitForTurnDiscoveryResponse() {\n if (!this.defer) {\n LoggerProxy.logger.warn('Roap:turnDiscovery#waitForTurnDiscoveryResponse --> TURN discovery is not in progress');\n\n return Promise.reject(new Error('waitForTurnDiscoveryResponse() called before sendRoapTurnDiscoveryRequest()'));\n }\n\n const {defer} = this;\n\n this.responseTimer = setTimeout(() => {\n LoggerProxy.logger.warn(`Roap:turnDiscovery#waitForTurnDiscoveryResponse --> timeout! no response arrived within ${TURN_DISCOVERY_TIMEOUT} seconds`);\n\n defer.reject(new Error('Timed out waiting for TURN_DISCOVERY_RESPONSE'));\n }, TURN_DISCOVERY_TIMEOUT * 1000);\n\n LoggerProxy.logger.info('Roap:turnDiscovery#waitForTurnDiscoveryResponse --> waiting for TURN_DISCOVERY_RESPONSE...');\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 handleTurnDiscoveryResponse(roapMessage) {\n const {headers} = roapMessage;\n\n if (!this.defer) {\n LoggerProxy.logger.warn('Roap:turnDiscovery#handleTurnDiscoveryResponse --> unexpected TURN discovery response');\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(expectedHeader.headerName.length + 1);\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(`Roap:turnDiscovery#handleTurnDiscoveryResponse --> missing some headers, received: ${JSON.stringify(headers)}`);\n this.defer.reject(new Error(`TURN_DISCOVERY_RESPONSE missing some headers: ${JSON.stringify(headers)}`));\n }\n else {\n LoggerProxy.logger.info(`Roap:turnDiscovery#handleTurnDiscoveryResponse --> received a valid response, url=${this.turnInfo.url}`);\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, isReconnecting) {\n const seq = meeting.roapSeq + 1;\n\n if (this.defer) {\n LoggerProxy.logger.warn('Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> already in progress');\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,\n };\n\n LoggerProxy.logger.info('Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> sending TURN_DISCOVERY_REQUEST');\n\n return this.roapRequest\n .sendRoap({\n roapMessage,\n correlationId: meeting.correlationId,\n locusSelfUrl: meeting.selfUrl,\n mediaId: isReconnecting ? '' : meeting.mediaId,\n audioMuted: meeting.isAudioMuted(),\n videoMuted: meeting.isVideoMuted(),\n meetingId: meeting.id\n })\n .then(({mediaConnections}) => {\n meeting.setRoapSeq(seq);\n\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) {\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: meeting.roapSeq\n },\n locusSelfUrl: meeting.selfUrl,\n mediaId: meeting.mediaId,\n correlationId: meeting.correlationId,\n audioMuted: meeting.isAudioMuted(),\n videoMuted: meeting.isVideoMuted(),\n meetingId: meeting.id\n });\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 * @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 * @returns {Promise}\n */\n doTurnDiscovery(meeting, isReconnecting) {\n const isAnyClusterReachable = meeting.webex.meetings.reachability.isAnyClusterReachable();\n\n if (isAnyClusterReachable) {\n LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> reachability has not failed, skipping TURN discovery');\n return Promise.resolve(undefined);\n }\n\n if (!meeting.config.experimental.enableTurnDiscovery) {\n LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery disabled in config, skipping it');\n\n return Promise.resolve(undefined);\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 this.turnInfo;\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(`Roap:turnDiscovery#doTurnDiscovery --> TURN discovery failed, continuing without TURN: ${e}`);\n\n Metrics.sendBehavioralMetric(\n BEHAVIORAL_METRICS.TURN_DISCOVERY_FAILURE,\n {\n correlation_id: meeting.correlationId,\n locus_id: meeting.locusUrl.split('/').pop(),\n reason: e.message,\n stack: e.stack\n }\n );\n\n return Promise.resolve(undefined);\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"names":["TURN_DISCOVERY_TIMEOUT","TurnDiscovery","roapRequest","turnInfo","url","username","password","defer","LoggerProxy","logger","warn","reject","Error","responseTimer","setTimeout","info","promise","roapMessage","headers","expectedHeaders","headerName","field","foundHeaders","forEach","receivedHeader","expectedHeader","startsWith","substring","length","clearTimeout","undefined","resolve","meeting","isReconnecting","seq","roapSeq","Defer","messageType","ROAP","ROAP_TYPES","TURN_DISCOVERY_REQUEST","version","ROAP_VERSION","sendRoap","correlationId","locusSelfUrl","selfUrl","mediaId","audioMuted","isAudioMuted","videoMuted","isVideoMuted","meetingId","id","then","mediaConnections","setRoapSeq","updateMediaConnections","OK","isAnyClusterReachable","webex","meetings","reachability","turnServerInfo","turnDiscoverySkippedReason","config","experimental","enableTurnDiscovery","sendRoapTurnDiscoveryRequest","waitForTurnDiscoveryResponse","sendRoapOK","catch","e","Metrics","sendBehavioralMetric","BEHAVIORAL_METRICS","TURN_DISCOVERY_FAILURE","correlation_id","locus_id","locusUrl","split","pop","reason","message","stack"],"sources":["turnDiscovery.ts"],"sourcesContent":["import {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';\n\nconst TURN_DISCOVERY_TIMEOUT = 10; // in seconds\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 /**\n * waits for TURN_DISCOVERY_RESPONSE message to arrive\n *\n * @returns {Promise}\n * @private\n * @memberof Roap\n */\n waitForTurnDiscoveryResponse() {\n if (!this.defer) {\n LoggerProxy.logger.warn('Roap:turnDiscovery#waitForTurnDiscoveryResponse --> TURN discovery is not in progress');\n\n return Promise.reject(new Error('waitForTurnDiscoveryResponse() called before sendRoapTurnDiscoveryRequest()'));\n }\n\n const {defer} = this;\n\n this.responseTimer = setTimeout(() => {\n LoggerProxy.logger.warn(`Roap:turnDiscovery#waitForTurnDiscoveryResponse --> timeout! no response arrived within ${TURN_DISCOVERY_TIMEOUT} seconds`);\n\n defer.reject(new Error('Timed out waiting for TURN_DISCOVERY_RESPONSE'));\n }, TURN_DISCOVERY_TIMEOUT * 1000);\n\n LoggerProxy.logger.info('Roap:turnDiscovery#waitForTurnDiscoveryResponse --> waiting for TURN_DISCOVERY_RESPONSE...');\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 handleTurnDiscoveryResponse(roapMessage) {\n const {headers} = roapMessage;\n\n if (!this.defer) {\n LoggerProxy.logger.warn('Roap:turnDiscovery#handleTurnDiscoveryResponse --> unexpected TURN discovery response');\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(expectedHeader.headerName.length + 1);\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(`Roap:turnDiscovery#handleTurnDiscoveryResponse --> missing some headers, received: ${JSON.stringify(headers)}`);\n this.defer.reject(new Error(`TURN_DISCOVERY_RESPONSE missing some headers: ${JSON.stringify(headers)}`));\n }\n else {\n LoggerProxy.logger.info(`Roap:turnDiscovery#handleTurnDiscoveryResponse --> received a valid response, url=${this.turnInfo.url}`);\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, isReconnecting) {\n const seq = meeting.roapSeq + 1;\n\n if (this.defer) {\n LoggerProxy.logger.warn('Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> already in progress');\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,\n };\n\n LoggerProxy.logger.info('Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> sending TURN_DISCOVERY_REQUEST');\n\n return this.roapRequest\n .sendRoap({\n roapMessage,\n correlationId: meeting.correlationId,\n locusSelfUrl: meeting.selfUrl,\n mediaId: isReconnecting ? '' : meeting.mediaId,\n audioMuted: meeting.isAudioMuted(),\n videoMuted: meeting.isVideoMuted(),\n meetingId: meeting.id\n })\n .then(({mediaConnections}) => {\n meeting.setRoapSeq(seq);\n\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) {\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: meeting.roapSeq\n },\n locusSelfUrl: meeting.selfUrl,\n mediaId: meeting.mediaId,\n correlationId: meeting.correlationId,\n audioMuted: meeting.isAudioMuted(),\n videoMuted: meeting.isVideoMuted(),\n meetingId: meeting.id\n });\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 * @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 * @returns {Promise}\n */\n doTurnDiscovery(meeting, isReconnecting) {\n const isAnyClusterReachable = meeting.webex.meetings.reachability.isAnyClusterReachable();\n\n if (isAnyClusterReachable) {\n LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> reachability has not failed, skipping TURN discovery');\n return Promise.resolve({turnServerInfo: undefined, turnDiscoverySkippedReason: 'reachability'});\n }\n\n if (!meeting.config.experimental.enableTurnDiscovery) {\n LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery disabled in config, skipping it');\n\n return Promise.resolve({turnServerInfo: undefined, turnDiscoverySkippedReason: 'config'});\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(`Roap:turnDiscovery#doTurnDiscovery --> TURN discovery failed, continuing without TURN: ${e}`);\n\n Metrics.sendBehavioralMetric(\n BEHAVIORAL_METRICS.TURN_DISCOVERY_FAILURE,\n {\n correlation_id: meeting.correlationId,\n locus_id: meeting.locusUrl.split('/').pop(),\n reason: e.message,\n stack: e.stack\n }\n );\n\n return Promise.resolve({turnServerInfo: undefined, turnDiscoverySkippedReason: undefined});\n });\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/plugin-meetings",
3
- "version": "2.33.1",
3
+ "version": "2.34.0",
4
4
  "description": "",
5
5
  "license": "Cisco EULA (https://www.cisco.com/c/en/us/products/end-user-license-agreement.html)",
6
6
  "contributors": [
@@ -24,30 +24,30 @@
24
24
  ]
25
25
  },
26
26
  "devDependencies": {
27
- "@webex/plugin-meetings": "2.33.1",
28
- "@webex/test-helper-chai": "2.33.1",
29
- "@webex/test-helper-mocha": "2.33.1",
30
- "@webex/test-helper-mock-webex": "2.33.1",
31
- "@webex/test-helper-retry": "2.33.1",
32
- "@webex/test-helper-test-users": "2.33.1",
27
+ "@webex/plugin-meetings": "2.34.0",
28
+ "@webex/test-helper-chai": "2.34.0",
29
+ "@webex/test-helper-mocha": "2.34.0",
30
+ "@webex/test-helper-mock-webex": "2.34.0",
31
+ "@webex/test-helper-retry": "2.34.0",
32
+ "@webex/test-helper-test-users": "2.34.0",
33
33
  "chai": "^4.3.4",
34
34
  "chai-as-promised": "^7.1.1",
35
35
  "jsdom-global": "3.0.2",
36
36
  "sinon": "^9.2.4"
37
37
  },
38
38
  "dependencies": {
39
- "@webex/common": "2.33.1",
39
+ "@webex/common": "2.34.0",
40
40
  "@webex/internal-media-core": "^0.0.7-beta",
41
- "@webex/internal-plugin-conversation": "2.33.1",
42
- "@webex/internal-plugin-device": "2.33.1",
43
- "@webex/internal-plugin-mercury": "2.33.1",
44
- "@webex/internal-plugin-metrics": "2.33.1",
45
- "@webex/internal-plugin-support": "2.33.1",
46
- "@webex/internal-plugin-user": "2.33.1",
47
- "@webex/plugin-people": "2.33.1",
48
- "@webex/plugin-rooms": "2.33.1",
41
+ "@webex/internal-plugin-conversation": "2.34.0",
42
+ "@webex/internal-plugin-device": "2.34.0",
43
+ "@webex/internal-plugin-mercury": "2.34.0",
44
+ "@webex/internal-plugin-metrics": "2.34.0",
45
+ "@webex/internal-plugin-support": "2.34.0",
46
+ "@webex/internal-plugin-user": "2.34.0",
47
+ "@webex/plugin-people": "2.34.0",
48
+ "@webex/plugin-rooms": "2.34.0",
49
49
  "@webex/ts-sdp": "^1.0.1",
50
- "@webex/webex-core": "2.33.1",
50
+ "@webex/webex-core": "2.34.0",
51
51
  "bowser": "^2.11.0",
52
52
  "btoa": "^1.2.1",
53
53
  "dotenv": "^4.0.0",
@@ -4184,6 +4184,9 @@ export default class Meeting extends StatelessWebexPlugin {
4184
4184
  addMedia(options = {}) {
4185
4185
  const LOG_HEADER = 'Meeting:index#addMedia -->';
4186
4186
 
4187
+ let turnDiscoverySkippedReason;
4188
+ let turnServerUsed = false;
4189
+
4187
4190
  if (this.meetingState !== FULL_STATE.ACTIVE) {
4188
4191
  return Promise.reject(new MeetingNotActiveError());
4189
4192
  }
@@ -4225,7 +4228,12 @@ export default class Meeting extends StatelessWebexPlugin {
4225
4228
 
4226
4229
  return MeetingUtil.validateOptions(options)
4227
4230
  .then(() => this.roap.doTurnDiscovery(this, false))
4228
- .then((turnServerInfo) => {
4231
+ .then((turnDiscoveryObject) => {
4232
+ ({turnDiscoverySkippedReason} = turnDiscoveryObject);
4233
+ turnServerUsed = !turnDiscoverySkippedReason;
4234
+
4235
+ const {turnServerInfo} = turnDiscoveryObject;
4236
+
4229
4237
  this.mediaProperties.setMediaPeerConnection(MediaUtil.createPeerConnection(turnServerInfo));
4230
4238
  this.setMercuryListener();
4231
4239
  PeerConnectionManager.setPeerConnectionEvents(this);
@@ -4266,7 +4274,9 @@ export default class Meeting extends StatelessWebexPlugin {
4266
4274
  correlation_id: this.correlationId,
4267
4275
  locus_id: this.locusUrl.split('/').pop(),
4268
4276
  reason: error.message,
4269
- stack: error.stack
4277
+ stack: error.stack,
4278
+ turnDiscoverySkippedReason,
4279
+ turnServerUsed
4270
4280
  }
4271
4281
  );
4272
4282
 
@@ -4376,7 +4386,9 @@ export default class Meeting extends StatelessWebexPlugin {
4376
4386
  locus_id: this.locusUrl.split('/').pop(),
4377
4387
  reason: error.message,
4378
4388
  stack: error.stack,
4379
- code: error.code
4389
+ code: error.code,
4390
+ turnDiscoverySkippedReason,
4391
+ turnServerUsed
4380
4392
  }
4381
4393
  );
4382
4394
 
@@ -206,13 +206,13 @@ export default class TurnDiscovery {
206
206
 
207
207
  if (isAnyClusterReachable) {
208
208
  LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> reachability has not failed, skipping TURN discovery');
209
- return Promise.resolve(undefined);
209
+ return Promise.resolve({turnServerInfo: undefined, turnDiscoverySkippedReason: 'reachability'});
210
210
  }
211
211
 
212
212
  if (!meeting.config.experimental.enableTurnDiscovery) {
213
213
  LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery disabled in config, skipping it');
214
214
 
215
- return Promise.resolve(undefined);
215
+ return Promise.resolve({turnServerInfo: undefined, turnDiscoverySkippedReason: 'config'});
216
216
  }
217
217
 
218
218
  return this.sendRoapTurnDiscoveryRequest(meeting, isReconnecting)
@@ -223,7 +223,7 @@ export default class TurnDiscovery {
223
223
 
224
224
  LoggerProxy.logger.info('Roap:turnDiscovery#doTurnDiscovery --> TURN discovery completed');
225
225
 
226
- return this.turnInfo;
226
+ return {turnServerInfo: this.turnInfo, turnDiscoverySkippedReason: undefined};
227
227
  })
228
228
  .catch((e) => {
229
229
  // we catch any errors and resolve with no turn information so that the normal call join flow can continue without TURN
@@ -239,7 +239,7 @@ export default class TurnDiscovery {
239
239
  }
240
240
  );
241
241
 
242
- return Promise.resolve(undefined);
242
+ return Promise.resolve({turnServerInfo: undefined, turnDiscoverySkippedReason: undefined});
243
243
  });
244
244
  }
245
245
  }
@@ -920,7 +920,7 @@ describe('plugin-meetings', () => {
920
920
  meeting.mediaProperties.peerConnection.connectionState = CONSTANTS.CONNECTION_STATE.CONNECTED;
921
921
  resolve();
922
922
  }));
923
- meeting.roap.doTurnDiscovery = sinon.stub().resolves();
923
+ meeting.roap.doTurnDiscovery = sinon.stub().resolves({turnServerInfo: {}, turnDiscoverySkippedReason: undefined});
924
924
  PeerConnectionManager.setContentSlides = sinon.stub().returns(true);
925
925
  });
926
926
 
@@ -961,6 +961,39 @@ describe('plugin-meetings', () => {
961
961
  await meeting.addMedia().catch((err) => {
962
962
  assert.exists(err);
963
963
  assert.isNull(meeting.statsAnalyzer);
964
+ assert(Metrics.sendBehavioralMetric.calledOnce);
965
+ assert.calledWith(
966
+ Metrics.sendBehavioralMetric,
967
+ BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE, {
968
+ correlation_id: meeting.correlationId,
969
+ locus_id: meeting.locusUrl.split('/').pop(),
970
+ reason: err.message,
971
+ stack: err.stack,
972
+ code: err.code,
973
+ turnDiscoverySkippedReason: undefined,
974
+ turnServerUsed: true
975
+ }
976
+ );
977
+ });
978
+ });
979
+
980
+ it('checks metrics called with skipped reason config', async () => {
981
+ meeting.roap.doTurnDiscovery = sinon.stub().resolves({turnServerInfo: undefined, turnDiscoverySkippedReason: 'config'});
982
+ meeting.meetingState = 'ACTIVE';
983
+ await meeting.addMedia().catch((err) => {
984
+ assert.exists(err);
985
+ assert(Metrics.sendBehavioralMetric.calledOnce);
986
+ assert.calledWith(
987
+ Metrics.sendBehavioralMetric,
988
+ BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE, {
989
+ correlation_id: meeting.correlationId,
990
+ locus_id: meeting.locusUrl.split('/').pop(),
991
+ reason: err.message,
992
+ stack: err.stack,
993
+ turnDiscoverySkippedReason: 'config',
994
+ turnServerUsed: false
995
+ }
996
+ );
964
997
  });
965
998
  });
966
999
 
@@ -970,6 +1003,18 @@ describe('plugin-meetings', () => {
970
1003
  await meeting.addMedia().catch((err) => {
971
1004
  assert.exists(err);
972
1005
  assert.isNull(meeting.mediaProperties.peerConnection);
1006
+ assert(Metrics.sendBehavioralMetric.calledOnce);
1007
+ assert.calledWith(
1008
+ Metrics.sendBehavioralMetric,
1009
+ BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE, {
1010
+ correlation_id: meeting.correlationId,
1011
+ locus_id: meeting.locusUrl.split('/').pop(),
1012
+ reason: err.message,
1013
+ stack: err.stack,
1014
+ turnDiscoverySkippedReason: undefined,
1015
+ turnServerUsed: true
1016
+ }
1017
+ );
973
1018
  });
974
1019
  });
975
1020
 
@@ -1035,6 +1080,8 @@ describe('plugin-meetings', () => {
1035
1080
  });
1036
1081
 
1037
1082
  it('should attach the media and return promise', async () => {
1083
+ meeting.roap.doTurnDiscovery = sinon.stub().resolves({turnServerInfo: undefined, turnDiscoverySkippedReason: undefined});
1084
+
1038
1085
  meeting.meetingState = 'ACTIVE';
1039
1086
  MediaUtil.createPeerConnection.resetHistory();
1040
1087
  const media = meeting.addMedia({
@@ -1065,10 +1112,14 @@ describe('plugin-meetings', () => {
1065
1112
  meeting.meetingState = 'ACTIVE';
1066
1113
  MediaUtil.createPeerConnection.resetHistory();
1067
1114
 
1115
+
1068
1116
  meeting.roap.doTurnDiscovery = sinon.stub().resolves({
1069
- url: FAKE_TURN_URL,
1070
- username: FAKE_TURN_USER,
1071
- password: FAKE_TURN_PASSWORD
1117
+ turnServerInfo: {
1118
+ url: FAKE_TURN_URL,
1119
+ username: FAKE_TURN_USER,
1120
+ password: FAKE_TURN_PASSWORD
1121
+ },
1122
+ turnServerSkippedReason: undefined
1072
1123
  });
1073
1124
  const media = meeting.addMedia({
1074
1125
  mediaSettings: {}
@@ -1087,6 +1138,7 @@ describe('plugin-meetings', () => {
1087
1138
  });
1088
1139
 
1089
1140
  it('should attach the media and return promise', async () => {
1141
+ meeting.roap.doTurnDiscovery = sinon.stub().resolves({turnServerInfo: undefined, turnDiscoverySkippedReason: undefined});
1090
1142
  meeting.meetingState = 'ACTIVE';
1091
1143
  meeting.mediaProperties.peerConnection.connectionState = 'DISCONNECTED';
1092
1144
  const media = meeting.addMedia({
@@ -117,14 +117,15 @@ describe('TurnDiscovery', () => {
117
117
  // check that we've sent OK
118
118
  await checkRoapMessageSent('OK', 0);
119
119
 
120
- const turnInfo = await result;
120
+ const {turnServerInfo, turnDiscoverySkippedReason} = await result;
121
121
 
122
- assert.deepEqual(turnInfo, {
122
+ assert.deepEqual(turnServerInfo, {
123
123
  url: FAKE_TURN_URL,
124
124
  username: FAKE_TURN_USERNAME,
125
125
  password: FAKE_TURN_PASSWORD
126
126
  });
127
127
 
128
+ assert.isUndefined(turnDiscoverySkippedReason);
128
129
  });
129
130
 
130
131
  it('sends TURN_DISCOVERY_REQUEST with empty mediaId when isReconnecting is true', async () => {
@@ -152,13 +153,14 @@ describe('TurnDiscovery', () => {
152
153
  // check that we've sent OK
153
154
  await checkRoapMessageSent('OK', 0);
154
155
 
155
- const turnInfo = await result;
156
+ const {turnServerInfo, turnDiscoverySkippedReason} = await result;
156
157
 
157
- assert.deepEqual(turnInfo, {
158
+ assert.deepEqual(turnServerInfo, {
158
159
  url: FAKE_TURN_URL,
159
160
  username: FAKE_TURN_USERNAME,
160
161
  password: FAKE_TURN_PASSWORD
161
162
  });
163
+ assert.isUndefined(turnDiscoverySkippedReason);
162
164
  });
163
165
 
164
166
  it('ignores any extra, unexpected headers in the response', async () => {
@@ -187,13 +189,13 @@ describe('TurnDiscovery', () => {
187
189
  // check that we've sent OK and still parsed the headers we care about
188
190
  await checkRoapMessageSent('OK', 0);
189
191
 
190
- const turnInfo = await result;
191
-
192
- assert.deepEqual(turnInfo, {
192
+ const {turnServerInfo, turnDiscoverySkippedReason} = await result;
193
+ assert.deepEqual(turnServerInfo, {
193
194
  url: FAKE_TURN_URL,
194
195
  username: FAKE_TURN_USERNAME,
195
196
  password: FAKE_TURN_PASSWORD
196
197
  });
198
+ assert.isUndefined(turnDiscoverySkippedReason);
197
199
  });
198
200
 
199
201
  it('resolves with undefined if turn discovery feature is disabled in config', async () => {
@@ -203,7 +205,10 @@ describe('TurnDiscovery', () => {
203
205
 
204
206
  const result = await new TurnDiscovery(mockRoapRequest).doTurnDiscovery(testMeeting);
205
207
 
206
- assert.isUndefined(result);
208
+ const {turnServerInfo, turnDiscoverySkippedReason} = result;
209
+
210
+ assert.isUndefined(turnServerInfo);
211
+ assert.equal(turnDiscoverySkippedReason, 'config');
207
212
  assert.notCalled(mockRoapRequest.sendRoap);
208
213
  assert.notCalled(Metrics.sendBehavioralMetric);
209
214
 
@@ -218,7 +223,10 @@ describe('TurnDiscovery', () => {
218
223
 
219
224
  const result = await td.doTurnDiscovery(testMeeting, false);
220
225
 
221
- assert.isUndefined(result);
226
+ const {turnServerInfo, turnDiscoverySkippedReason} = result;
227
+
228
+ assert.isUndefined(turnServerInfo);
229
+ assert.isUndefined(turnDiscoverySkippedReason);
222
230
  checkFailureMetricsSent();
223
231
  });
224
232
 
@@ -227,7 +235,10 @@ describe('TurnDiscovery', () => {
227
235
  testMeeting.webex.meetings.reachability.isAnyClusterReachable = () => true;
228
236
  const result = await new TurnDiscovery(mockRoapRequest).doTurnDiscovery(testMeeting);
229
237
 
230
- assert.isUndefined(result);
238
+ const {turnServerInfo, turnDiscoverySkippedReason} = result;
239
+
240
+ assert.isUndefined(turnServerInfo);
241
+ assert.equal(turnDiscoverySkippedReason, 'reachability');
231
242
  assert.notCalled(mockRoapRequest.sendRoap);
232
243
  assert.notCalled(Metrics.sendBehavioralMetric);
233
244
  testMeeting.webex.meetings.reachability.isAnyClusterReachable = prev;
@@ -242,9 +253,10 @@ describe('TurnDiscovery', () => {
242
253
  await clock.tickAsync(10 * 1000);
243
254
  await testUtils.flushPromises();
244
255
 
245
- const turnInfo = await promise;
256
+ const {turnServerInfo, turnDiscoverySkippedReason} = await promise;
246
257
 
247
- assert.isUndefined(turnInfo);
258
+ assert.isUndefined(turnServerInfo);
259
+ assert.isUndefined(turnDiscoverySkippedReason);
248
260
  checkFailureMetricsSent();
249
261
  });
250
262
 
@@ -260,9 +272,10 @@ describe('TurnDiscovery', () => {
260
272
  ]
261
273
  });
262
274
  await testUtils.flushPromises();
263
- const turnInfo = await turnDiscoveryPromise;
275
+ const {turnServerInfo, turnDiscoverySkippedReason} = await turnDiscoveryPromise;
264
276
 
265
- assert.isUndefined(turnInfo);
277
+ assert.isUndefined(turnServerInfo);
278
+ assert.isUndefined(turnDiscoverySkippedReason);
266
279
  checkFailureMetricsSent();
267
280
  });
268
281
 
@@ -274,9 +287,10 @@ describe('TurnDiscovery', () => {
274
287
  td.handleTurnDiscoveryResponse({});
275
288
 
276
289
  await testUtils.flushPromises();
277
- const turnInfo = await turnDiscoveryPromise;
290
+ const {turnServerInfo, turnDiscoverySkippedReason} = await turnDiscoveryPromise;
278
291
 
279
- assert.isUndefined(turnInfo);
292
+ assert.isUndefined(turnServerInfo);
293
+ assert.isUndefined(turnDiscoverySkippedReason);
280
294
  checkFailureMetricsSent();
281
295
  });
282
296
 
@@ -288,9 +302,10 @@ describe('TurnDiscovery', () => {
288
302
  td.handleTurnDiscoveryResponse({headers: []});
289
303
 
290
304
  await testUtils.flushPromises();
291
- const turnInfo = await turnDiscoveryPromise;
305
+ const {turnServerInfo, turnDiscoverySkippedReason}= await turnDiscoveryPromise;
292
306
 
293
- assert.isUndefined(turnInfo);
307
+ assert.isUndefined(turnServerInfo);
308
+ assert.isUndefined(turnDiscoverySkippedReason);
294
309
  checkFailureMetricsSent();
295
310
  });
296
311
 
@@ -321,9 +336,10 @@ describe('TurnDiscovery', () => {
321
336
  // check that we've sent OK
322
337
  await checkRoapMessageSent('OK', 0);
323
338
 
324
- const turnInfo = await turnDiscoveryPromise;
339
+ const {turnServerInfo, turnDiscoverySkippedReason} = await turnDiscoveryPromise;
325
340
 
326
- assert.isUndefined(turnInfo);
341
+ assert.isUndefined(turnServerInfo);
342
+ assert.isUndefined(turnDiscoverySkippedReason);
327
343
  checkFailureMetricsSent();
328
344
  });
329
345
  });