@webex/plugin-meetings 3.0.0-stream-classes.3 → 3.0.0-stream-classes.4
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.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/constants.js +2 -0
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/meeting/locusMediaRequest.js +1 -1
- package/dist/meeting/locusMediaRequest.js.map +1 -1
- package/dist/meeting/request.js +23 -13
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +33 -3
- package/dist/meeting/util.js.map +1 -1
- package/dist/meetings/index.js +3 -4
- package/dist/meetings/index.js.map +1 -1
- package/dist/metrics/constants.js +1 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/reachability/index.js +2 -11
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.js.map +1 -1
- package/dist/reconnection-manager/index.js +26 -22
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/roap/index.js +5 -7
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +1 -0
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +3 -4
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/package.json +1 -1
- package/src/constants.ts +2 -2
- package/src/meeting/locusMediaRequest.ts +2 -3
- package/src/meeting/request.ts +15 -5
- package/src/meeting/util.ts +36 -2
- package/src/meetings/index.ts +2 -2
- package/src/metrics/constants.ts +1 -0
- package/src/reachability/index.ts +4 -10
- package/src/reachability/request.ts +1 -1
- package/src/reconnection-manager/index.ts +13 -11
- package/src/roap/index.ts +2 -4
- package/src/roap/request.ts +2 -1
- package/src/roap/turnDiscovery.ts +2 -3
- package/test/unit/spec/meeting/index.js +7 -5
- package/test/unit/spec/meeting/locusMediaRequest.ts +1 -2
- package/test/unit/spec/meeting/request.js +23 -0
- package/test/unit/spec/meeting/utils.js +73 -4
- package/test/unit/spec/meetings/index.js +66 -1
- package/test/unit/spec/reachability/index.ts +8 -8
- package/test/unit/spec/reconnection-manager/index.js +21 -0
- package/test/unit/spec/roap/index.ts +5 -1
- package/test/unit/spec/roap/turnDiscovery.ts +11 -4
|
@@ -18,6 +18,7 @@ var _metrics = _interopRequireDefault(require("../metrics"));
|
|
|
18
18
|
var _constants = _interopRequireDefault(require("../metrics/constants"));
|
|
19
19
|
var _loggerProxy = _interopRequireDefault(require("../common/logs/logger-proxy"));
|
|
20
20
|
var _constants2 = require("../constants");
|
|
21
|
+
var _util = _interopRequireDefault(require("../meeting/util"));
|
|
21
22
|
// @ts-ignore - Types not available for @webex/common
|
|
22
23
|
|
|
23
24
|
var TURN_DISCOVERY_TIMEOUT = 10; // in seconds
|
|
@@ -158,7 +159,7 @@ var TurnDiscovery = /*#__PURE__*/function () {
|
|
|
158
159
|
meetingId: meeting.id,
|
|
159
160
|
locusMediaRequest: meeting.locusMediaRequest,
|
|
160
161
|
// @ts-ignore - because of meeting.webex
|
|
161
|
-
ipVersion:
|
|
162
|
+
ipVersion: _util.default.getIpVersion(meeting.webex)
|
|
162
163
|
}).then(function (_ref) {
|
|
163
164
|
var mediaConnections = _ref.mediaConnections;
|
|
164
165
|
if (mediaConnections) {
|
|
@@ -189,9 +190,7 @@ var TurnDiscovery = /*#__PURE__*/function () {
|
|
|
189
190
|
// @ts-ignore - fix type
|
|
190
191
|
mediaId: meeting.mediaId,
|
|
191
192
|
meetingId: meeting.id,
|
|
192
|
-
locusMediaRequest: meeting.locusMediaRequest
|
|
193
|
-
// @ts-ignore - because of meeting.webex
|
|
194
|
-
ipVersion: meeting.webex.meetings.reachability.getIpVersion()
|
|
193
|
+
locusMediaRequest: meeting.locusMediaRequest
|
|
195
194
|
});
|
|
196
195
|
}
|
|
197
196
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["TURN_DISCOVERY_TIMEOUT","TURN_DISCOVERY_SEQ","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","Defer","messageType","ROAP","ROAP_TYPES","TURN_DISCOVERY_REQUEST","version","ROAP_VERSION","seq","sendRoap","locusSelfUrl","selfUrl","mediaId","meetingId","id","locusMediaRequest","ipVersion","webex","meetings","reachability","getIpVersion","then","mediaConnections","updateMediaConnections","OK","isAnyClusterReachable","config","experimental","enableTurnDiscovery","getSkipReason","skipReason","turnDiscoverySkippedReason","turnServerInfo","sendRoapTurnDiscoveryRequest","waitForTurnDiscoveryResponse","sendRoapOK","catch","e","Metrics","sendBehavioralMetric","BEHAVIORAL_METRICS","TURN_DISCOVERY_FAILURE","correlation_id","correlationId","locus_id","locusUrl","split","pop","reason","message","stack"],"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';\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: meeting.webex.meetings.reachability.getIpVersion(),\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 // @ts-ignore - because of meeting.webex\n ipVersion: meeting.webex.meetings.reachability.getIpVersion(),\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 // @ts-ignore - fix type\n const isAnyClusterReachable = await meeting.webex.meetings.reachability.isAnyClusterReachable();\n\n if (isAnyClusterReachable) {\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#getSkipReason --> reachability has not failed, skipping TURN discovery'\n );\n\n return 'reachability';\n }\n\n // @ts-ignore - fix type\n if (!meeting.config.experimental.enableTurnDiscovery) {\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#getSkipReason --> TURN discovery disabled in config, skipping it'\n );\n\n return 'config';\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 * @returns {Promise}\n */\n async doTurnDiscovery(meeting: Meeting, isReconnecting?: boolean) {\n const turnDiscoverySkippedReason = await this.getSkipReason(meeting);\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":["TURN_DISCOVERY_TIMEOUT","TURN_DISCOVERY_SEQ","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","Defer","messageType","ROAP","ROAP_TYPES","TURN_DISCOVERY_REQUEST","version","ROAP_VERSION","seq","sendRoap","locusSelfUrl","selfUrl","mediaId","meetingId","id","locusMediaRequest","ipVersion","MeetingUtil","getIpVersion","webex","then","mediaConnections","updateMediaConnections","OK","meetings","reachability","isAnyClusterReachable","config","experimental","enableTurnDiscovery","getSkipReason","skipReason","turnDiscoverySkippedReason","turnServerInfo","sendRoapTurnDiscoveryRequest","waitForTurnDiscoveryResponse","sendRoapOK","catch","e","Metrics","sendBehavioralMetric","BEHAVIORAL_METRICS","TURN_DISCOVERY_FAILURE","correlation_id","correlationId","locus_id","locusUrl","split","pop","reason","message","stack"],"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 // @ts-ignore - fix type\n const isAnyClusterReachable = await meeting.webex.meetings.reachability.isAnyClusterReachable();\n\n if (isAnyClusterReachable) {\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#getSkipReason --> reachability has not failed, skipping TURN discovery'\n );\n\n return 'reachability';\n }\n\n // @ts-ignore - fix type\n if (!meeting.config.experimental.enableTurnDiscovery) {\n LoggerProxy.logger.info(\n 'Roap:turnDiscovery#getSkipReason --> TURN discovery disabled in config, skipping it'\n );\n\n return 'config';\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 * @returns {Promise}\n */\n async doTurnDiscovery(meeting: Meeting, isReconnecting?: boolean) {\n const turnDiscoverySkippedReason = await this.getSkipReason(meeting);\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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"}
|
package/package.json
CHANGED
package/src/constants.ts
CHANGED
|
@@ -1242,8 +1242,8 @@ export const DEFAULT_MEETING_INFO_REQUEST_BODY = {
|
|
|
1242
1242
|
/** the values for IP_VERSION are fixed and defined in Orpheus API */
|
|
1243
1243
|
export const IP_VERSION = {
|
|
1244
1244
|
unknown: 0,
|
|
1245
|
-
only_ipv4: 4,
|
|
1246
|
-
only_ipv6: 6,
|
|
1245
|
+
only_ipv4: 4, // we know we have ipv4, we don't know or we don't have ipv6
|
|
1246
|
+
only_ipv6: 6, // we know we have ipv6, we don't know or we don't have ipv4
|
|
1247
1247
|
ipv4_and_ipv6: 1,
|
|
1248
1248
|
} as const;
|
|
1249
1249
|
|
|
@@ -16,7 +16,7 @@ export type RoapRequest = {
|
|
|
16
16
|
reachability: any;
|
|
17
17
|
sequence?: any;
|
|
18
18
|
joinCookie: any; // any, because this is opaque to the client, we pass whatever object we got from one backend component (Orpheus) to the other (Locus)
|
|
19
|
-
ipVersion
|
|
19
|
+
ipVersion?: IP_VERSION;
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
export type LocalMuteRequest = {
|
|
@@ -28,7 +28,6 @@ export type LocalMuteRequest = {
|
|
|
28
28
|
audioMuted?: boolean;
|
|
29
29
|
videoMuted?: boolean;
|
|
30
30
|
};
|
|
31
|
-
ipVersion: IP_VERSION;
|
|
32
31
|
};
|
|
33
32
|
|
|
34
33
|
export type Request = RoapRequest | LocalMuteRequest;
|
|
@@ -204,7 +203,7 @@ export class LocusMediaRequest extends WebexPlugin {
|
|
|
204
203
|
correlationId: this.config.correlationId,
|
|
205
204
|
clientMediaPreferences: {
|
|
206
205
|
preferTranscoding: this.config.preferTranscoding,
|
|
207
|
-
ipver: request.ipVersion,
|
|
206
|
+
ipver: request.type === 'RoapMessage' ? request.ipVersion : undefined,
|
|
208
207
|
},
|
|
209
208
|
};
|
|
210
209
|
|
package/src/meeting/request.ts
CHANGED
|
@@ -108,6 +108,7 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
108
108
|
sipUri: string;
|
|
109
109
|
deviceUrl: string;
|
|
110
110
|
locusUrl: string;
|
|
111
|
+
locusClusterUrl: string;
|
|
111
112
|
resourceId: string;
|
|
112
113
|
correlationId: string;
|
|
113
114
|
ensureConversation: boolean;
|
|
@@ -124,7 +125,7 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
124
125
|
locale?: string;
|
|
125
126
|
deviceCapabilities?: Array<string>;
|
|
126
127
|
liveAnnotationSupported: boolean;
|
|
127
|
-
ipVersion
|
|
128
|
+
ipVersion?: IP_VERSION;
|
|
128
129
|
}) {
|
|
129
130
|
const {
|
|
130
131
|
asResourceOccupant,
|
|
@@ -133,6 +134,7 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
133
134
|
permissionToken,
|
|
134
135
|
deviceUrl,
|
|
135
136
|
locusUrl,
|
|
137
|
+
locusClusterUrl,
|
|
136
138
|
resourceId,
|
|
137
139
|
correlationId,
|
|
138
140
|
ensureConversation,
|
|
@@ -214,10 +216,18 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
214
216
|
url = `${locusUrl}/${PARTICIPANT}`;
|
|
215
217
|
} else if (inviteeAddress || meetingNumber) {
|
|
216
218
|
try {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
219
|
+
let clusterUrl;
|
|
220
|
+
|
|
221
|
+
if (locusClusterUrl) {
|
|
222
|
+
clusterUrl = `https://${locusClusterUrl}/locus/api/v1`;
|
|
223
|
+
} else {
|
|
224
|
+
// @ts-ignore
|
|
225
|
+
await this.webex.internal.services.waitForCatalog('postauth');
|
|
226
|
+
// @ts-ignore
|
|
227
|
+
clusterUrl = this.webex.internal.services.get('locus');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
url = `${clusterUrl}/${LOCI}/${CALL}`;
|
|
221
231
|
body.invitee = {
|
|
222
232
|
address: inviteeAddress || `wbxmn:${meetingNumber}`,
|
|
223
233
|
};
|
package/src/meeting/util.ts
CHANGED
|
@@ -13,7 +13,9 @@ import {
|
|
|
13
13
|
FULL_STATE,
|
|
14
14
|
SELF_POLICY,
|
|
15
15
|
EVENT_TRIGGERS,
|
|
16
|
+
IP_VERSION,
|
|
16
17
|
} from '../constants';
|
|
18
|
+
import BrowserDetection from '../common/browser-detection';
|
|
17
19
|
import IntentToJoinError from '../common/errors/intent-to-join';
|
|
18
20
|
import JoinMeetingError from '../common/errors/join-meeting';
|
|
19
21
|
import ParameterError from '../common/errors/parameter';
|
|
@@ -73,7 +75,6 @@ const MeetingUtil = {
|
|
|
73
75
|
audioMuted,
|
|
74
76
|
videoMuted,
|
|
75
77
|
},
|
|
76
|
-
ipVersion: meeting.getWebexObject().meetings.reachability.getIpVersion(),
|
|
77
78
|
})
|
|
78
79
|
.then((response) => {
|
|
79
80
|
// @ts-ignore
|
|
@@ -92,6 +93,38 @@ const MeetingUtil = {
|
|
|
92
93
|
|
|
93
94
|
isPinOrGuest: (err) => err?.body?.errorCode && INTENT_TO_JOIN.includes(err.body.errorCode),
|
|
94
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Returns the current state of knowledge about whether we are on an ipv4-only or ipv6-only or mixed (ipv4 and ipv6) network.
|
|
98
|
+
* The return value matches the possible values of "ipver" parameter used by the backend APIs.
|
|
99
|
+
*
|
|
100
|
+
* @param {Object} webex webex instance
|
|
101
|
+
* @returns {IP_VERSION|undefined} ipver value to be passed to the backend APIs or undefined if we should not pass any value to the backend
|
|
102
|
+
*/
|
|
103
|
+
getIpVersion(webex: any): IP_VERSION | undefined {
|
|
104
|
+
const {supportsIpV4, supportsIpV6} = webex.internal.device.ipNetworkDetector;
|
|
105
|
+
|
|
106
|
+
if (BrowserDetection().isBrowser('firefox')) {
|
|
107
|
+
// our ipv6 solution relies on FQDN ICE candidates, but Firefox doesn't support them,
|
|
108
|
+
// see https://bugzilla.mozilla.org/show_bug.cgi?id=1713128
|
|
109
|
+
// so for Firefox we don't want the backend to activate the "ipv6 feature"
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (supportsIpV4 && supportsIpV6) {
|
|
114
|
+
return IP_VERSION.ipv4_and_ipv6;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (supportsIpV4) {
|
|
118
|
+
return IP_VERSION.only_ipv4;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (supportsIpV6) {
|
|
122
|
+
return IP_VERSION.only_ipv6;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return IP_VERSION.unknown;
|
|
126
|
+
},
|
|
127
|
+
|
|
95
128
|
joinMeeting: (meeting, options) => {
|
|
96
129
|
if (!meeting) {
|
|
97
130
|
return Promise.reject(new ParameterError('You need a meeting object.'));
|
|
@@ -113,6 +146,7 @@ const MeetingUtil = {
|
|
|
113
146
|
meetingNumber: meeting.meetingNumber,
|
|
114
147
|
deviceUrl: meeting.deviceUrl,
|
|
115
148
|
locusUrl: meeting.locusUrl,
|
|
149
|
+
locusClusterUrl: meeting.meetingInfo?.locusClusterUrl,
|
|
116
150
|
correlationId: meeting.correlationId,
|
|
117
151
|
roapMessage: options.roapMessage,
|
|
118
152
|
permissionToken: meeting.permissionToken,
|
|
@@ -126,7 +160,7 @@ const MeetingUtil = {
|
|
|
126
160
|
locale: options.locale,
|
|
127
161
|
deviceCapabilities: options.deviceCapabilities,
|
|
128
162
|
liveAnnotationSupported: options.liveAnnotationSupported,
|
|
129
|
-
ipVersion: meeting.getWebexObject()
|
|
163
|
+
ipVersion: MeetingUtil.getIpVersion(meeting.getWebexObject()),
|
|
130
164
|
})
|
|
131
165
|
.then((res) => {
|
|
132
166
|
// @ts-ignore
|
package/src/meetings/index.ts
CHANGED
|
@@ -887,6 +887,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
887
887
|
'Meetings:index#uploadLogs --> Upload logs for meeting completed.',
|
|
888
888
|
uploadResult
|
|
889
889
|
);
|
|
890
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.UPLOAD_LOGS_SUCCESS, options);
|
|
890
891
|
Trigger.trigger(
|
|
891
892
|
this,
|
|
892
893
|
{
|
|
@@ -921,8 +922,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
921
922
|
);
|
|
922
923
|
|
|
923
924
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.UPLOAD_LOGS_FAILURE, {
|
|
924
|
-
|
|
925
|
-
meetingId: options.meetingsId,
|
|
925
|
+
...options,
|
|
926
926
|
reason: uploadError.message,
|
|
927
927
|
stack: uploadError.stack,
|
|
928
928
|
code: uploadError.code,
|
package/src/metrics/constants.ts
CHANGED
|
@@ -40,6 +40,7 @@ const BEHAVIORAL_METRICS = {
|
|
|
40
40
|
PEERCONNECTION_FAILURE: 'js_sdk_peerConnection_failures',
|
|
41
41
|
INVALID_ICE_CANDIDATE: 'js_sdk_invalid_ice_candidate',
|
|
42
42
|
UPLOAD_LOGS_FAILURE: 'js_sdk_upload_logs_failure',
|
|
43
|
+
UPLOAD_LOGS_SUCCESS: 'js_sdk_upload_logs_success',
|
|
43
44
|
RECEIVE_TRANSCRIPTION_FAILURE: 'js_sdk_receive_transcription_failure',
|
|
44
45
|
FETCH_MEETING_INFO_V1_SUCCESS: 'js_sdk_fetch_meeting_info_v1_success',
|
|
45
46
|
FETCH_MEETING_INFO_V1_FAILURE: 'js_sdk_fetch_meeting_info_v1_failure',
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
import _ from 'lodash';
|
|
8
8
|
|
|
9
9
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
10
|
-
import
|
|
10
|
+
import MeetingUtil from '../meeting/util';
|
|
11
|
+
|
|
12
|
+
import {ICE_GATHERING_STATE, CONNECTION_STATE, REACHABILITY} from '../constants';
|
|
11
13
|
|
|
12
14
|
import ReachabilityRequest from './request';
|
|
13
15
|
|
|
@@ -71,7 +73,7 @@ export default class Reachability {
|
|
|
71
73
|
// Fetch clusters and measure latency
|
|
72
74
|
try {
|
|
73
75
|
const {clusters, joinCookie} = await this.reachabilityRequest.getClusters(
|
|
74
|
-
|
|
76
|
+
MeetingUtil.getIpVersion(this.webex)
|
|
75
77
|
);
|
|
76
78
|
|
|
77
79
|
// Perform Reachability Check
|
|
@@ -134,14 +136,6 @@ export default class Reachability {
|
|
|
134
136
|
return reachable;
|
|
135
137
|
}
|
|
136
138
|
|
|
137
|
-
/**
|
|
138
|
-
* Returns what we know about the IP version of the networks we're connected to.
|
|
139
|
-
* @returns {IP_VERSION}
|
|
140
|
-
*/
|
|
141
|
-
getIpVersion(): IP_VERSION {
|
|
142
|
-
return IP_VERSION.unknown;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
139
|
/**
|
|
146
140
|
* Generate peerConnection config settings
|
|
147
141
|
* @param {object} cluster
|
|
@@ -33,7 +33,7 @@ class ReachabilityRequest {
|
|
|
33
33
|
* @param {IP_VERSION} ipVersion information about current ip network we're on
|
|
34
34
|
* @returns {Promise}
|
|
35
35
|
*/
|
|
36
|
-
getClusters = (ipVersion
|
|
36
|
+
getClusters = (ipVersion?: IP_VERSION): Promise<{clusters: ClusterList; joinCookie: any}> =>
|
|
37
37
|
this.webex
|
|
38
38
|
.request({
|
|
39
39
|
method: HTTP_VERBS.GET,
|
|
@@ -443,17 +443,19 @@ export default class ReconnectionManager {
|
|
|
443
443
|
}
|
|
444
444
|
}
|
|
445
445
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
446
|
+
if (!this.webex.credentials.isUnverifiedGuest) {
|
|
447
|
+
try {
|
|
448
|
+
LoggerProxy.logger.info(
|
|
449
|
+
'ReconnectionManager:index#executeReconnection --> Updating meeting data from server.'
|
|
450
|
+
);
|
|
451
|
+
await this.webex.meetings.syncMeetings();
|
|
452
|
+
} catch (syncError) {
|
|
453
|
+
LoggerProxy.logger.info(
|
|
454
|
+
'ReconnectionManager:index#executeReconnection --> Unable to sync meetings, reconnecting.',
|
|
455
|
+
syncError
|
|
456
|
+
);
|
|
457
|
+
throw new NeedsRetryError(syncError);
|
|
458
|
+
}
|
|
457
459
|
}
|
|
458
460
|
|
|
459
461
|
// TODO: try to improve this logic as the reconnection manager saves the instance of deleted meeting object
|
package/src/roap/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ import LoggerProxy from '../common/logs/logger-proxy';
|
|
|
7
7
|
import RoapRequest from './request';
|
|
8
8
|
import TurnDiscovery from './turnDiscovery';
|
|
9
9
|
import Meeting from '../meeting';
|
|
10
|
+
import MeetingUtil from '../meeting/util';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Roap options
|
|
@@ -100,7 +101,6 @@ export default class Roap extends StatelessWebexPlugin {
|
|
|
100
101
|
mediaId: options.mediaId,
|
|
101
102
|
meetingId: meeting.id,
|
|
102
103
|
locusMediaRequest: meeting.locusMediaRequest,
|
|
103
|
-
ipVersion: meeting.webex.meetings.reachability.getIpVersion(),
|
|
104
104
|
})
|
|
105
105
|
.then(() => {
|
|
106
106
|
LoggerProxy.logger.log(`Roap:index#sendRoapOK --> ROAP OK sent with seq ${options.seq}`);
|
|
@@ -135,7 +135,6 @@ export default class Roap extends StatelessWebexPlugin {
|
|
|
135
135
|
mediaId: options.mediaId,
|
|
136
136
|
meetingId: meeting.id,
|
|
137
137
|
locusMediaRequest: meeting.locusMediaRequest,
|
|
138
|
-
ipVersion: meeting.webex.meetings.reachability.getIpVersion(),
|
|
139
138
|
});
|
|
140
139
|
}
|
|
141
140
|
|
|
@@ -165,7 +164,6 @@ export default class Roap extends StatelessWebexPlugin {
|
|
|
165
164
|
mediaId: options.mediaId,
|
|
166
165
|
meetingId: meeting.id,
|
|
167
166
|
locusMediaRequest: meeting.locusMediaRequest,
|
|
168
|
-
ipVersion: meeting.webex.meetings.reachability.getIpVersion(),
|
|
169
167
|
})
|
|
170
168
|
.then(() => {
|
|
171
169
|
LoggerProxy.logger.log(
|
|
@@ -204,7 +202,7 @@ export default class Roap extends StatelessWebexPlugin {
|
|
|
204
202
|
meetingId: meeting.id,
|
|
205
203
|
preferTranscoding: !meeting.isMultistream,
|
|
206
204
|
locusMediaRequest: meeting.locusMediaRequest,
|
|
207
|
-
ipVersion: meeting.webex
|
|
205
|
+
ipVersion: MeetingUtil.getIpVersion(meeting.webex),
|
|
208
206
|
})
|
|
209
207
|
.then(({locus, mediaConnections}) => {
|
|
210
208
|
if (mediaConnections) {
|
package/src/roap/request.ts
CHANGED
|
@@ -63,6 +63,7 @@ export default class RoapRequest extends StatelessWebexPlugin {
|
|
|
63
63
|
* @param {String} options.mediaId
|
|
64
64
|
* @param {String} options.correlationId
|
|
65
65
|
* @param {String} options.meetingId
|
|
66
|
+
* @param {IP_VERSION} options.ipVersion only required for offers
|
|
66
67
|
* @returns {Promise} returns the response/failure of the request
|
|
67
68
|
*/
|
|
68
69
|
async sendRoap(options: {
|
|
@@ -70,7 +71,7 @@ export default class RoapRequest extends StatelessWebexPlugin {
|
|
|
70
71
|
locusSelfUrl: string;
|
|
71
72
|
mediaId: string;
|
|
72
73
|
meetingId: string;
|
|
73
|
-
ipVersion
|
|
74
|
+
ipVersion?: IP_VERSION;
|
|
74
75
|
locusMediaRequest?: LocusMediaRequest;
|
|
75
76
|
}) {
|
|
76
77
|
const {roapMessage, locusSelfUrl, mediaId, meetingId, locusMediaRequest, ipVersion} = options;
|
|
@@ -8,6 +8,7 @@ import {ROAP} from '../constants';
|
|
|
8
8
|
|
|
9
9
|
import RoapRequest from './request';
|
|
10
10
|
import Meeting from '../meeting';
|
|
11
|
+
import MeetingUtil from '../meeting/util';
|
|
11
12
|
|
|
12
13
|
const TURN_DISCOVERY_TIMEOUT = 10; // in seconds
|
|
13
14
|
|
|
@@ -183,7 +184,7 @@ export default class TurnDiscovery {
|
|
|
183
184
|
meetingId: meeting.id,
|
|
184
185
|
locusMediaRequest: meeting.locusMediaRequest,
|
|
185
186
|
// @ts-ignore - because of meeting.webex
|
|
186
|
-
ipVersion: meeting.webex
|
|
187
|
+
ipVersion: MeetingUtil.getIpVersion(meeting.webex),
|
|
187
188
|
})
|
|
188
189
|
.then(({mediaConnections}) => {
|
|
189
190
|
if (mediaConnections) {
|
|
@@ -214,8 +215,6 @@ export default class TurnDiscovery {
|
|
|
214
215
|
mediaId: meeting.mediaId,
|
|
215
216
|
meetingId: meeting.id,
|
|
216
217
|
locusMediaRequest: meeting.locusMediaRequest,
|
|
217
|
-
// @ts-ignore - because of meeting.webex
|
|
218
|
-
ipVersion: meeting.webex.meetings.reachability.getIpVersion(),
|
|
219
218
|
});
|
|
220
219
|
}
|
|
221
220
|
|
|
@@ -1674,6 +1674,8 @@ describe('plugin-meetings', () => {
|
|
|
1674
1674
|
beforeEach(() => {
|
|
1675
1675
|
clock = sinon.useFakeTimers();
|
|
1676
1676
|
|
|
1677
|
+
sinon.stub(MeetingUtil, 'getIpVersion').returns(IP_VERSION.unknown);
|
|
1678
|
+
|
|
1677
1679
|
meeting.deviceUrl = 'deviceUrl';
|
|
1678
1680
|
meeting.config.deviceType = 'web';
|
|
1679
1681
|
meeting.isMultistream = isMultistream;
|
|
@@ -1687,12 +1689,11 @@ describe('plugin-meetings', () => {
|
|
|
1687
1689
|
meeting.webex.meetings.geoHintInfo = {regionCode: 'EU', countryCode: 'UK'};
|
|
1688
1690
|
meeting.webex.meetings.reachability = {
|
|
1689
1691
|
isAnyClusterReachable: sinon.stub().resolves(true),
|
|
1690
|
-
getIpVersion: () => IP_VERSION.unknown,
|
|
1691
1692
|
};
|
|
1692
1693
|
meeting.roap.doTurnDiscovery = sinon
|
|
1693
1694
|
.stub()
|
|
1694
1695
|
.resolves({turnServerInfo: {}, turnDiscoverySkippedReason: 'reachability'});
|
|
1695
|
-
|
|
1696
|
+
|
|
1696
1697
|
StaticConfig.set({bandwidth: {audio: 1234, video: 5678, startBitrate: 9876}});
|
|
1697
1698
|
|
|
1698
1699
|
// setup things that are expected to be the same across all the tests and are actually irrelevant for these tests
|
|
@@ -1768,6 +1769,7 @@ describe('plugin-meetings', () => {
|
|
|
1768
1769
|
|
|
1769
1770
|
afterEach(() => {
|
|
1770
1771
|
clock.restore();
|
|
1772
|
+
sinon.restore();
|
|
1771
1773
|
});
|
|
1772
1774
|
|
|
1773
1775
|
// helper function that waits until all promises are resolved and any queued up /media requests to Locus are sent out
|
|
@@ -1855,7 +1857,7 @@ describe('plugin-meetings', () => {
|
|
|
1855
1857
|
],
|
|
1856
1858
|
clientMediaPreferences: {
|
|
1857
1859
|
preferTranscoding: !meeting.isMultistream,
|
|
1858
|
-
ipver:
|
|
1860
|
+
ipver: undefined
|
|
1859
1861
|
},
|
|
1860
1862
|
respOnlySdp: true,
|
|
1861
1863
|
usingResource: null,
|
|
@@ -1936,7 +1938,7 @@ describe('plugin-meetings', () => {
|
|
|
1936
1938
|
// and that it was the only /media request that was sent
|
|
1937
1939
|
assert.calledOnce(locusMediaRequestStub);
|
|
1938
1940
|
});
|
|
1939
|
-
|
|
1941
|
+
|
|
1940
1942
|
it('addMedia() works correctly when media is enabled with streams to publish', async () => {
|
|
1941
1943
|
await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}});
|
|
1942
1944
|
await simulateRoapOffer();
|
|
@@ -2083,7 +2085,7 @@ describe('plugin-meetings', () => {
|
|
|
2083
2085
|
} else {
|
|
2084
2086
|
assert.notCalled(locusMediaRequestStub);
|
|
2085
2087
|
}
|
|
2086
|
-
|
|
2088
|
+
|
|
2087
2089
|
if (isMultistream) {
|
|
2088
2090
|
assert.calledOnceWithExactly(meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream, fakeMicrophoneStream);
|
|
2089
2091
|
} else {
|
|
@@ -68,7 +68,6 @@ describe('LocusMediaRequest.send()', () => {
|
|
|
68
68
|
mediaId: 'mediaId',
|
|
69
69
|
selfUrl: 'fakeMeetingSelfUrl',
|
|
70
70
|
muteOptions: {},
|
|
71
|
-
ipVersion: IP_VERSION.only_ipv6
|
|
72
71
|
};
|
|
73
72
|
|
|
74
73
|
const createExpectedLocalMuteBody = (expectedMute:{audioMuted: boolean, videoMuted: boolean}, sequence = undefined) => {
|
|
@@ -89,7 +88,7 @@ describe('LocusMediaRequest.send()', () => {
|
|
|
89
88
|
],
|
|
90
89
|
clientMediaPreferences: {
|
|
91
90
|
preferTranscoding: true,
|
|
92
|
-
ipver:
|
|
91
|
+
ipver: undefined,
|
|
93
92
|
},
|
|
94
93
|
};
|
|
95
94
|
|
|
@@ -237,6 +237,29 @@ describe('plugin-meetings', () => {
|
|
|
237
237
|
assert.equal(requestParams.body.invitee.address, 'sipUrl');
|
|
238
238
|
});
|
|
239
239
|
|
|
240
|
+
it('sends uses the locusClusterUrl if available', async () => {
|
|
241
|
+
const deviceUrl = 'deviceUrl';
|
|
242
|
+
const correlationId = 'random-uuid';
|
|
243
|
+
const roapMessage = 'roap-message';
|
|
244
|
+
const inviteeAddress = 'sipUrl';
|
|
245
|
+
const locusClusterUrl = 'locusClusterUrl';
|
|
246
|
+
|
|
247
|
+
await meetingsRequest.joinMeeting({
|
|
248
|
+
deviceUrl,
|
|
249
|
+
correlationId,
|
|
250
|
+
roapMessage,
|
|
251
|
+
locusClusterUrl,
|
|
252
|
+
inviteeAddress,
|
|
253
|
+
});
|
|
254
|
+
const requestParams = meetingsRequest.request.getCall(0).args[0];
|
|
255
|
+
|
|
256
|
+
assert.equal(requestParams.method, 'POST');
|
|
257
|
+
assert.equal(
|
|
258
|
+
requestParams.uri,
|
|
259
|
+
'https://locusClusterUrl/locus/api/v1/loci/call?alternateRedirect=true'
|
|
260
|
+
);
|
|
261
|
+
});
|
|
262
|
+
|
|
240
263
|
it('adds deviceCapabilities to request when breakouts are supported', async () => {
|
|
241
264
|
await meetingsRequest.joinMeeting({
|
|
242
265
|
breakoutsSupported: true,
|