@webex/plugin-meetings 2.33.2 → 2.35.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.
- package/dist/constants.js +4 -4
- package/dist/constants.js.map +1 -1
- package/dist/media/properties.js +139 -0
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/index.js +106 -102
- package/dist/meeting/index.js.map +1 -1
- package/dist/roap/turnDiscovery.js +16 -4
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/package.json +17 -17
- package/src/constants.ts +8 -8
- package/src/media/properties.js +97 -0
- package/src/meeting/index.js +111 -110
- package/src/roap/turnDiscovery.ts +4 -4
- package/test/unit/spec/media/properties.ts +305 -0
- package/test/unit/spec/meeting/index.js +94 -4
- package/test/unit/spec/roap/turnDiscovery.ts +36 -20
|
@@ -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(
|
|
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(
|
|
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
|
|
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(
|
|
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.
|
|
3
|
+
"version": "2.35.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.
|
|
28
|
-
"@webex/test-helper-chai": "2.
|
|
29
|
-
"@webex/test-helper-mocha": "2.
|
|
30
|
-
"@webex/test-helper-mock-webex": "2.
|
|
31
|
-
"@webex/test-helper-retry": "2.
|
|
32
|
-
"@webex/test-helper-test-users": "2.
|
|
27
|
+
"@webex/plugin-meetings": "2.35.0",
|
|
28
|
+
"@webex/test-helper-chai": "2.35.0",
|
|
29
|
+
"@webex/test-helper-mocha": "2.35.0",
|
|
30
|
+
"@webex/test-helper-mock-webex": "2.35.0",
|
|
31
|
+
"@webex/test-helper-retry": "2.35.0",
|
|
32
|
+
"@webex/test-helper-test-users": "2.35.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.
|
|
39
|
+
"@webex/common": "2.35.0",
|
|
40
40
|
"@webex/internal-media-core": "^0.0.7-beta",
|
|
41
|
-
"@webex/internal-plugin-conversation": "2.
|
|
42
|
-
"@webex/internal-plugin-device": "2.
|
|
43
|
-
"@webex/internal-plugin-mercury": "2.
|
|
44
|
-
"@webex/internal-plugin-metrics": "2.
|
|
45
|
-
"@webex/internal-plugin-support": "2.
|
|
46
|
-
"@webex/internal-plugin-user": "2.
|
|
47
|
-
"@webex/plugin-people": "2.
|
|
48
|
-
"@webex/plugin-rooms": "2.
|
|
41
|
+
"@webex/internal-plugin-conversation": "2.35.0",
|
|
42
|
+
"@webex/internal-plugin-device": "2.35.0",
|
|
43
|
+
"@webex/internal-plugin-mercury": "2.35.0",
|
|
44
|
+
"@webex/internal-plugin-metrics": "2.35.0",
|
|
45
|
+
"@webex/internal-plugin-support": "2.35.0",
|
|
46
|
+
"@webex/internal-plugin-user": "2.35.0",
|
|
47
|
+
"@webex/plugin-people": "2.35.0",
|
|
48
|
+
"@webex/plugin-rooms": "2.35.0",
|
|
49
49
|
"@webex/ts-sdp": "^1.0.1",
|
|
50
|
-
"@webex/webex-core": "2.
|
|
50
|
+
"@webex/webex-core": "2.35.0",
|
|
51
51
|
"bowser": "^2.11.0",
|
|
52
52
|
"btoa": "^1.2.1",
|
|
53
53
|
"dotenv": "^4.0.0",
|
package/src/constants.ts
CHANGED
|
@@ -972,7 +972,7 @@ export const QUALITY_LEVELS = {
|
|
|
972
972
|
};
|
|
973
973
|
|
|
974
974
|
|
|
975
|
-
export const
|
|
975
|
+
export const AVAILABLE_RESOLUTIONS = {
|
|
976
976
|
'360p': {
|
|
977
977
|
video: {
|
|
978
978
|
width: {
|
|
@@ -1024,13 +1024,13 @@ export const AVALIABLE_RESOLUTIONS = {
|
|
|
1024
1024
|
};
|
|
1025
1025
|
|
|
1026
1026
|
export const VIDEO_RESOLUTIONS = {
|
|
1027
|
-
[QUALITY_LEVELS.LOW]:
|
|
1028
|
-
[QUALITY_LEVELS.MEDIUM]:
|
|
1029
|
-
[QUALITY_LEVELS.HIGH]:
|
|
1030
|
-
[QUALITY_LEVELS['360p']]:
|
|
1031
|
-
[QUALITY_LEVELS['480p']]:
|
|
1032
|
-
[QUALITY_LEVELS['720p']]:
|
|
1033
|
-
[QUALITY_LEVELS['1080p']]:
|
|
1027
|
+
[QUALITY_LEVELS.LOW]: AVAILABLE_RESOLUTIONS['480p'],
|
|
1028
|
+
[QUALITY_LEVELS.MEDIUM]: AVAILABLE_RESOLUTIONS['720p'],
|
|
1029
|
+
[QUALITY_LEVELS.HIGH]: AVAILABLE_RESOLUTIONS['1080p'],
|
|
1030
|
+
[QUALITY_LEVELS['360p']]: AVAILABLE_RESOLUTIONS['360p'],
|
|
1031
|
+
[QUALITY_LEVELS['480p']]: AVAILABLE_RESOLUTIONS['480p'],
|
|
1032
|
+
[QUALITY_LEVELS['720p']]: AVAILABLE_RESOLUTIONS['720p'],
|
|
1033
|
+
[QUALITY_LEVELS['1080p']]: AVAILABLE_RESOLUTIONS['1080p'],
|
|
1034
1034
|
};
|
|
1035
1035
|
|
|
1036
1036
|
/**
|
package/src/media/properties.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ICE_STATE,
|
|
2
3
|
MEETINGS,
|
|
4
|
+
PC_BAIL_TIMEOUT,
|
|
3
5
|
QUALITY_LEVELS
|
|
4
6
|
} from '../constants';
|
|
5
7
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
@@ -195,4 +197,99 @@ export default class MediaProperties {
|
|
|
195
197
|
this.unsetLocalVideoTrack();
|
|
196
198
|
this.unsetRemoteMedia();
|
|
197
199
|
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Waits until ice connection is established
|
|
203
|
+
*
|
|
204
|
+
* @returns {Promise<void>}
|
|
205
|
+
*/
|
|
206
|
+
waitForIceConnectedState() {
|
|
207
|
+
const isIceConnected = () => (
|
|
208
|
+
this.peerConnection.iceConnectionState === ICE_STATE.CONNECTED ||
|
|
209
|
+
this.peerConnection.iceConnectionState === ICE_STATE.COMPLETED
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
if (isIceConnected()) {
|
|
213
|
+
return Promise.resolve();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return new Promise((resolve, reject) => {
|
|
217
|
+
let timer;
|
|
218
|
+
|
|
219
|
+
const iceListener = () => {
|
|
220
|
+
LoggerProxy.logger.log(`Media:properties#waitForIceConnectedState --> ice state: ${this.peerConnection.iceConnectionState}, conn state: ${this.peerConnection.connectionState}`);
|
|
221
|
+
|
|
222
|
+
if (isIceConnected()) {
|
|
223
|
+
clearTimeout(timer);
|
|
224
|
+
this.peerConnection.removeEventListener('iceconnectionstatechange', iceListener);
|
|
225
|
+
resolve();
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
timer = setTimeout(() => {
|
|
230
|
+
this.peerConnection.removeEventListener('iceconnectionstatechange', iceListener);
|
|
231
|
+
reject();
|
|
232
|
+
}, PC_BAIL_TIMEOUT);
|
|
233
|
+
|
|
234
|
+
this.peerConnection.addEventListener('iceconnectionstatechange', iceListener);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Returns the type of a connection that has been established
|
|
240
|
+
*
|
|
241
|
+
* @returns {Promise<'UDP' | 'TCP' | 'TURN-TLS' | 'TURN-TCP' | 'TURN-UDP' | 'unknown'>}
|
|
242
|
+
*/
|
|
243
|
+
async getCurrentConnectionType() {
|
|
244
|
+
// we can only get the connection type after ICE connection has been established
|
|
245
|
+
await this.waitForIceConnectedState();
|
|
246
|
+
|
|
247
|
+
const allStatsReports = [];
|
|
248
|
+
|
|
249
|
+
try {
|
|
250
|
+
// eslint-disable-next-line no-await-in-loop
|
|
251
|
+
const statsResult = await this.peerConnection.getStats();
|
|
252
|
+
|
|
253
|
+
statsResult.forEach((report) => allStatsReports.push(report));
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
LoggerProxy.logger.warn(`Media:properties#getCurrentConnectionType --> getStats() failed: ${error}`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const successfulCandidatePairs = allStatsReports.filter(
|
|
260
|
+
(report) => report.type === 'candidate-pair' && report.state?.toLowerCase() === 'succeeded'
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
let foundConnectionType = 'unknown';
|
|
264
|
+
|
|
265
|
+
// all of the successful pairs should have the same connection type, so just return the type for the first one
|
|
266
|
+
successfulCandidatePairs.some((pair) => {
|
|
267
|
+
const localCandidate = allStatsReports.find((report) => report.type === 'local-candidate' && report.id === pair.localCandidateId);
|
|
268
|
+
|
|
269
|
+
if (localCandidate === undefined) {
|
|
270
|
+
LoggerProxy.logger.warn(`Media:properties#getCurrentConnectionType --> failed to find local candidate "${pair.localCandidateId}" in getStats() results`);
|
|
271
|
+
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
let connectionType;
|
|
276
|
+
|
|
277
|
+
if (localCandidate.relayProtocol) {
|
|
278
|
+
connectionType = `TURN-${localCandidate.relayProtocol.toUpperCase()}`;
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
connectionType = localCandidate.protocol?.toUpperCase(); // it will be UDP or TCP
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (connectionType) {
|
|
285
|
+
foundConnectionType = connectionType;
|
|
286
|
+
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return false;
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
return foundConnectionType;
|
|
294
|
+
}
|
|
198
295
|
}
|
package/src/meeting/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import uuid from 'uuid';
|
|
2
|
-
import {cloneDeep, isEqual, pick} from 'lodash';
|
|
2
|
+
import {cloneDeep, isEqual, pick, isString} from 'lodash';
|
|
3
3
|
import {StatelessWebexPlugin} from '@webex/webex-core';
|
|
4
4
|
import {Media as WebRTCMedia} from '@webex/internal-media-core';
|
|
5
5
|
|
|
@@ -36,7 +36,6 @@ import {
|
|
|
36
36
|
_INCOMING_,
|
|
37
37
|
_JOIN_,
|
|
38
38
|
AUDIO,
|
|
39
|
-
CONNECTION_STATE,
|
|
40
39
|
CONTENT,
|
|
41
40
|
ENDED,
|
|
42
41
|
EVENT_TRIGGERS,
|
|
@@ -58,7 +57,6 @@ import {
|
|
|
58
57
|
ONLINE,
|
|
59
58
|
OFFLINE,
|
|
60
59
|
PASSWORD_STATUS,
|
|
61
|
-
PC_BAIL_TIMEOUT,
|
|
62
60
|
PSTN_STATUS,
|
|
63
61
|
QUALITY_LEVELS,
|
|
64
62
|
RECORDING_STATE,
|
|
@@ -2746,7 +2744,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2746
2744
|
const {localQualityLevel} = this.mediaProperties;
|
|
2747
2745
|
|
|
2748
2746
|
if (Number(localQualityLevel.slice(0, -1)) > height) {
|
|
2749
|
-
LoggerProxy.logger.
|
|
2747
|
+
LoggerProxy.logger.warn(`Meeting:index#setLocalVideoTrack --> Local video quality of ${localQualityLevel} not supported,
|
|
2750
2748
|
downscaling to highest possible resolution of ${height}p`);
|
|
2751
2749
|
|
|
2752
2750
|
this.mediaProperties.setLocalQualityLevel(`${height}p`);
|
|
@@ -4014,6 +4012,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4014
4012
|
LoggerProxy.logger.warn('Meeting:index#getMediaStreams --> Please use `meeting.shareScreen()` to manually start the screen share after successfully joining the meeting');
|
|
4015
4013
|
}
|
|
4016
4014
|
|
|
4015
|
+
if (audioVideo && isString(audioVideo)) {
|
|
4016
|
+
if (Object.keys(VIDEO_RESOLUTIONS).includes(audioVideo)) {
|
|
4017
|
+
this.mediaProperties.setLocalQualityLevel(audioVideo);
|
|
4018
|
+
audioVideo = {video: VIDEO_RESOLUTIONS[audioVideo].video};
|
|
4019
|
+
}
|
|
4020
|
+
else {
|
|
4021
|
+
throw new ParameterError(`${audioVideo} not supported. Either pass level from pre-defined resolutions or pass complete audioVideo object`);
|
|
4022
|
+
}
|
|
4023
|
+
}
|
|
4024
|
+
|
|
4017
4025
|
if (!audioVideo.video) {
|
|
4018
4026
|
audioVideo = {...audioVideo, video: {...audioVideo.video, ...VIDEO_RESOLUTIONS[this.mediaProperties.localQualityLevel].video}};
|
|
4019
4027
|
}
|
|
@@ -4184,6 +4192,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4184
4192
|
addMedia(options = {}) {
|
|
4185
4193
|
const LOG_HEADER = 'Meeting:index#addMedia -->';
|
|
4186
4194
|
|
|
4195
|
+
let turnDiscoverySkippedReason;
|
|
4196
|
+
let turnServerUsed = false;
|
|
4197
|
+
|
|
4187
4198
|
if (this.meetingState !== FULL_STATE.ACTIVE) {
|
|
4188
4199
|
return Promise.reject(new MeetingNotActiveError());
|
|
4189
4200
|
}
|
|
@@ -4225,7 +4236,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4225
4236
|
|
|
4226
4237
|
return MeetingUtil.validateOptions(options)
|
|
4227
4238
|
.then(() => this.roap.doTurnDiscovery(this, false))
|
|
4228
|
-
.then((
|
|
4239
|
+
.then((turnDiscoveryObject) => {
|
|
4240
|
+
({turnDiscoverySkippedReason} = turnDiscoveryObject);
|
|
4241
|
+
turnServerUsed = !turnDiscoverySkippedReason;
|
|
4242
|
+
|
|
4243
|
+
const {turnServerInfo} = turnDiscoveryObject;
|
|
4244
|
+
|
|
4229
4245
|
this.mediaProperties.setMediaPeerConnection(MediaUtil.createPeerConnection(turnServerInfo));
|
|
4230
4246
|
this.setMercuryListener();
|
|
4231
4247
|
PeerConnectionManager.setPeerConnectionEvents(this);
|
|
@@ -4238,127 +4254,110 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4238
4254
|
enableRtx: this.config.enableRtx,
|
|
4239
4255
|
enableExtmap: this.config.enableExtmap,
|
|
4240
4256
|
setStartLocalSDPGenRemoteSDPRecvDelay: this.setStartLocalSDPGenRemoteSDPRecvDelay.bind(this)
|
|
4241
|
-
})
|
|
4242
|
-
|
|
4243
|
-
|
|
4257
|
+
}))
|
|
4258
|
+
.then((peerConnection) => this.getDevices().then((devices) => {
|
|
4259
|
+
MeetingUtil.handleDeviceLogging(devices);
|
|
4244
4260
|
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4261
|
+
return peerConnection;
|
|
4262
|
+
}))
|
|
4263
|
+
.then((peerConnection) => {
|
|
4264
|
+
this.handleMediaLogging(this.mediaProperties);
|
|
4265
|
+
LoggerProxy.logger.info(`${LOG_HEADER} PeerConnection Received from attachMedia `);
|
|
4266
|
+
|
|
4267
|
+
this.setRemoteStream(peerConnection);
|
|
4268
|
+
if (this.config.stats.enableStatsAnalyzer) {
|
|
4269
|
+
// TODO: ** Dont re create StatsAnalyzer on reconnect or rejoin
|
|
4270
|
+
this.networkQualityMonitor = new NetworkQualityMonitor(this.config.stats);
|
|
4271
|
+
this.statsAnalyzer = new StatsAnalyzer(this.config.stats, this.networkQualityMonitor);
|
|
4272
|
+
this.setupStatsAnalyzerEventHandlers();
|
|
4273
|
+
this.networkQualityMonitor.on(EVENT_TRIGGERS.NETWORK_QUALITY, this.sendNetworkQualityEvent.bind(this));
|
|
4274
|
+
}
|
|
4275
|
+
})
|
|
4276
|
+
.catch((error) => {
|
|
4277
|
+
LoggerProxy.logger.error(`${LOG_HEADER} Error adding media , setting up peerconnection, `, error);
|
|
4250
4278
|
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4279
|
+
Metrics.sendBehavioralMetric(
|
|
4280
|
+
BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE,
|
|
4281
|
+
{
|
|
4282
|
+
correlation_id: this.correlationId,
|
|
4283
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
4284
|
+
reason: error.message,
|
|
4285
|
+
stack: error.stack,
|
|
4286
|
+
turnDiscoverySkippedReason,
|
|
4287
|
+
turnServerUsed
|
|
4258
4288
|
}
|
|
4259
|
-
|
|
4260
|
-
.catch((error) => {
|
|
4261
|
-
LoggerProxy.logger.error(`${LOG_HEADER} Error adding media , setting up peerconnection, `, error);
|
|
4262
|
-
|
|
4263
|
-
Metrics.sendBehavioralMetric(
|
|
4264
|
-
BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE,
|
|
4265
|
-
{
|
|
4266
|
-
correlation_id: this.correlationId,
|
|
4267
|
-
locus_id: this.locusUrl.split('/').pop(),
|
|
4268
|
-
reason: error.message,
|
|
4269
|
-
stack: error.stack
|
|
4270
|
-
}
|
|
4271
|
-
);
|
|
4289
|
+
);
|
|
4272
4290
|
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4291
|
+
throw error;
|
|
4292
|
+
})
|
|
4293
|
+
.then(() => new Promise((resolve, reject) => {
|
|
4294
|
+
let timerCount = 0;
|
|
4277
4295
|
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4296
|
+
// eslint-disable-next-line func-names
|
|
4297
|
+
// eslint-disable-next-line prefer-arrow-callback
|
|
4298
|
+
if (this.type === _CALL_) {
|
|
4299
|
+
resolve();
|
|
4300
|
+
}
|
|
4301
|
+
const joiningTimer = setInterval(() => {
|
|
4302
|
+
timerCount += 1;
|
|
4303
|
+
if (this.meetingState === FULL_STATE.ACTIVE) {
|
|
4304
|
+
clearInterval(joiningTimer);
|
|
4281
4305
|
resolve();
|
|
4282
4306
|
}
|
|
4283
|
-
const joiningTimer = setInterval(() => {
|
|
4284
|
-
timerCount += 1;
|
|
4285
|
-
if (this.meetingState === FULL_STATE.ACTIVE) {
|
|
4286
|
-
clearInterval(joiningTimer);
|
|
4287
|
-
resolve();
|
|
4288
|
-
}
|
|
4289
4307
|
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4308
|
+
if (timerCount === 4) {
|
|
4309
|
+
clearInterval(joiningTimer);
|
|
4310
|
+
reject(new Error('Meeting is still not active '));
|
|
4311
|
+
}
|
|
4312
|
+
}, 1000);
|
|
4313
|
+
}))
|
|
4314
|
+
.then(() =>
|
|
4315
|
+
logRequest(this.roap
|
|
4316
|
+
.sendRoapMediaRequest({
|
|
4317
|
+
sdp: this.mediaProperties.peerConnection.sdp,
|
|
4318
|
+
roapSeq: this.roapSeq,
|
|
4319
|
+
meeting: this // or can pass meeting ID
|
|
4320
|
+
}), {
|
|
4321
|
+
header: `${LOG_HEADER} Send Roap Media Request.`,
|
|
4322
|
+
success: `${LOG_HEADER} Successfully send roap media request`,
|
|
4323
|
+
failure: `${LOG_HEADER} Error joining the call on send roap media request, `
|
|
4295
4324
|
}))
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
success: `${LOG_HEADER} Successfully send roap media request`,
|
|
4305
|
-
failure: `${LOG_HEADER} Error joining the call on send roap media request, `
|
|
4306
|
-
}))
|
|
4307
|
-
.then(() => {
|
|
4308
|
-
const {peerConnection} = this.mediaProperties;
|
|
4309
|
-
|
|
4310
|
-
return new Promise((resolve, reject) => {
|
|
4311
|
-
if (peerConnection.connectionState === CONNECTION_STATE.CONNECTED) {
|
|
4312
|
-
LoggerProxy.logger.info(`${LOG_HEADER} PeerConnection CONNECTED`);
|
|
4313
|
-
|
|
4314
|
-
resolve(peerConnection);
|
|
4315
|
-
|
|
4316
|
-
return;
|
|
4317
|
-
}
|
|
4318
|
-
// Check if Peer Connection is STABLE (connected)
|
|
4319
|
-
const stabilityTimeout = setTimeout(() => {
|
|
4320
|
-
if (peerConnection.connectionState !== CONNECTION_STATE.CONNECTED) {
|
|
4321
|
-
// TODO: Fix this after the error code pr goes in
|
|
4322
|
-
reject(createMeetingsError(30202, 'Meeting connection failed'));
|
|
4323
|
-
}
|
|
4324
|
-
else {
|
|
4325
|
-
LoggerProxy.logger.info(`${LOG_HEADER} PeerConnection CONNECTED`);
|
|
4326
|
-
resolve(peerConnection);
|
|
4327
|
-
}
|
|
4328
|
-
}, PC_BAIL_TIMEOUT);
|
|
4329
|
-
|
|
4330
|
-
this.once(EVENT_TRIGGERS.MEDIA_READY, () => {
|
|
4331
|
-
LoggerProxy.logger.info(`${LOG_HEADER} PeerConnection CONNECTED, clearing stability timer.`);
|
|
4332
|
-
clearTimeout(stabilityTimeout);
|
|
4333
|
-
resolve(peerConnection);
|
|
4334
|
-
});
|
|
4335
|
-
});
|
|
4336
|
-
})
|
|
4337
|
-
.then(() => {
|
|
4338
|
-
if (mediaSettings && mediaSettings.sendShare && localShare) {
|
|
4339
|
-
if (this.state === MEETING_STATE.STATES.JOINED) {
|
|
4340
|
-
return this.share();
|
|
4341
|
-
}
|
|
4325
|
+
.then(
|
|
4326
|
+
() => this.mediaProperties.waitForIceConnectedState()
|
|
4327
|
+
.catch(() => {
|
|
4328
|
+
throw createMeetingsError(30202, 'Meeting connection failed');
|
|
4329
|
+
})
|
|
4330
|
+
)
|
|
4331
|
+
.then(() => {
|
|
4332
|
+
LoggerProxy.logger.info(`${LOG_HEADER} PeerConnection CONNECTED`);
|
|
4342
4333
|
|
|
4343
|
-
|
|
4344
|
-
|
|
4334
|
+
if (mediaSettings && mediaSettings.sendShare && localShare) {
|
|
4335
|
+
if (this.state === MEETING_STATE.STATES.JOINED) {
|
|
4336
|
+
return this.share();
|
|
4345
4337
|
}
|
|
4346
4338
|
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
correlation_id: this.correlationId,
|
|
4351
|
-
locus_id: this.locusUrl.split('/').pop()
|
|
4352
|
-
}
|
|
4353
|
-
);
|
|
4339
|
+
// When the self state changes to JOINED then request the floor
|
|
4340
|
+
this.floorGrantPending = true;
|
|
4341
|
+
}
|
|
4354
4342
|
|
|
4355
|
-
|
|
4356
|
-
|
|
4343
|
+
return {};
|
|
4344
|
+
})
|
|
4345
|
+
.then(() => this.mediaProperties.getCurrentConnectionType())
|
|
4346
|
+
.then((connectionType) => {
|
|
4347
|
+
Metrics.sendBehavioralMetric(
|
|
4348
|
+
BEHAVIORAL_METRICS.ADD_MEDIA_SUCCESS,
|
|
4349
|
+
{
|
|
4350
|
+
correlation_id: this.correlationId,
|
|
4351
|
+
locus_id: this.locusUrl.split('/').pop(),
|
|
4352
|
+
connectionType
|
|
4353
|
+
}
|
|
4354
|
+
);
|
|
4355
|
+
})
|
|
4357
4356
|
.catch((error) => {
|
|
4358
4357
|
// Clean up stats analyzer, peer connection, and turn off listeners
|
|
4359
4358
|
const stopStatsAnalyzer = (this.statsAnalyzer) ? this.statsAnalyzer.stopAnalyzer() : Promise.resolve();
|
|
4360
4359
|
|
|
4361
|
-
stopStatsAnalyzer
|
|
4360
|
+
return stopStatsAnalyzer
|
|
4362
4361
|
.then(() => {
|
|
4363
4362
|
this.statsAnalyzer = null;
|
|
4364
4363
|
|
|
@@ -4376,7 +4375,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4376
4375
|
locus_id: this.locusUrl.split('/').pop(),
|
|
4377
4376
|
reason: error.message,
|
|
4378
4377
|
stack: error.stack,
|
|
4379
|
-
code: error.code
|
|
4378
|
+
code: error.code,
|
|
4379
|
+
turnDiscoverySkippedReason,
|
|
4380
|
+
turnServerUsed
|
|
4380
4381
|
}
|
|
4381
4382
|
);
|
|
4382
4383
|
|
|
@@ -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
|
}
|