@webex/plugin-meetings 3.1.0-next.5 → 3.1.0-next.7
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/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/media/properties.js +102 -57
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/index.js +109 -46
- package/dist/meeting/index.js.map +1 -1
- package/dist/types/media/properties.d.ts +26 -2
- package/dist/types/meeting/index.d.ts +2 -4
- package/dist/webinar/index.js +1 -1
- package/package.json +3 -3
- package/src/media/properties.ts +67 -15
- package/src/meeting/index.ts +45 -3
- package/test/unit/spec/media/properties.ts +145 -140
- package/test/unit/spec/meeting/index.js +141 -4
|
@@ -84,10 +84,34 @@ export default class MediaProperties {
|
|
|
84
84
|
* @returns {Promise<void>}
|
|
85
85
|
*/
|
|
86
86
|
waitForMediaConnectionConnected(): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Returns ICE transport information:
|
|
89
|
+
* - selectedCandidatePairChanges - number of times the selected candidate pair was changed, it should be at least 1 for successful connections
|
|
90
|
+
* it will be -1 if browser doesn't supply this information
|
|
91
|
+
* - numTransports - number of transports (should be 1 if we're using bundle)
|
|
92
|
+
*
|
|
93
|
+
* @param {Array<any>} allStatsReports array of RTC stats reports
|
|
94
|
+
* @returns {Object}
|
|
95
|
+
*/
|
|
96
|
+
private getTransportInfo;
|
|
87
97
|
/**
|
|
88
98
|
* Returns the type of a connection that has been established
|
|
99
|
+
* It should be 'UDP' | 'TCP' | 'TURN-TLS' | 'TURN-TCP' | 'TURN-UDP' | 'unknown'
|
|
100
|
+
*
|
|
101
|
+
* If connection was not established, it returns 'unknown'
|
|
102
|
+
*
|
|
103
|
+
* @param {Array<any>} allStatsReports array of RTC stats reports
|
|
104
|
+
* @returns {string}
|
|
105
|
+
*/
|
|
106
|
+
private getConnectionType;
|
|
107
|
+
/**
|
|
108
|
+
* Returns information about current webrtc media connection
|
|
89
109
|
*
|
|
90
|
-
* @returns {Promise<
|
|
110
|
+
* @returns {Promise<Object>}
|
|
91
111
|
*/
|
|
92
|
-
|
|
112
|
+
getCurrentConnectionInfo(): Promise<{
|
|
113
|
+
connectionType: string;
|
|
114
|
+
selectedCandidatePairChanges: number;
|
|
115
|
+
numTransports: number;
|
|
116
|
+
}>;
|
|
93
117
|
}
|
|
@@ -454,6 +454,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
454
454
|
private deferSDPAnswer?;
|
|
455
455
|
private sdpResponseTimer?;
|
|
456
456
|
private hasMediaConnectionConnectedAtLeastOnce;
|
|
457
|
+
private joinWithMediaRetryInfo?;
|
|
457
458
|
/**
|
|
458
459
|
* @param {Object} attrs
|
|
459
460
|
* @param {Object} options
|
|
@@ -1078,10 +1079,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1078
1079
|
joinWithMedia(options?: {
|
|
1079
1080
|
joinOptions?: any;
|
|
1080
1081
|
mediaOptions?: AddMediaOptions;
|
|
1081
|
-
}):
|
|
1082
|
-
join: any;
|
|
1083
|
-
media: void;
|
|
1084
|
-
}>;
|
|
1082
|
+
}): any;
|
|
1085
1083
|
/**
|
|
1086
1084
|
* Initiates the reconnection of the media in the meeting
|
|
1087
1085
|
*
|
package/dist/webinar/index.js
CHANGED
|
@@ -62,7 +62,7 @@ var Webinar = _webexCore.WebexPlugin.extend({
|
|
|
62
62
|
updateCanManageWebcast: function updateCanManageWebcast(canManageWebcast) {
|
|
63
63
|
this.set('canManageWebcast', canManageWebcast);
|
|
64
64
|
},
|
|
65
|
-
version: "3.1.0-next.
|
|
65
|
+
version: "3.1.0-next.7"
|
|
66
66
|
});
|
|
67
67
|
var _default = exports.default = Webinar;
|
|
68
68
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"@webex/eslint-config-legacy": "0.0.0",
|
|
44
44
|
"@webex/jest-config-legacy": "0.0.0",
|
|
45
45
|
"@webex/legacy-tools": "0.0.0",
|
|
46
|
-
"@webex/plugin-meetings": "3.1.0-next.
|
|
46
|
+
"@webex/plugin-meetings": "3.1.0-next.7",
|
|
47
47
|
"@webex/plugin-rooms": "3.0.0-next.16",
|
|
48
48
|
"@webex/test-helper-chai": "3.0.0-next.14",
|
|
49
49
|
"@webex/test-helper-mocha": "3.0.0-next.14",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"@webex/internal-plugin-metrics": "3.0.0-next.14",
|
|
71
71
|
"@webex/internal-plugin-support": "3.0.0-next.16",
|
|
72
72
|
"@webex/internal-plugin-user": "3.0.0-next.14",
|
|
73
|
-
"@webex/internal-plugin-voicea": "3.1.0-next.
|
|
73
|
+
"@webex/internal-plugin-voicea": "3.1.0-next.7",
|
|
74
74
|
"@webex/media-helpers": "3.0.1-next.17",
|
|
75
75
|
"@webex/plugin-people": "3.0.0-next.16",
|
|
76
76
|
"@webex/plugin-rooms": "3.0.0-next.16",
|
|
@@ -91,5 +91,5 @@
|
|
|
91
91
|
"//": [
|
|
92
92
|
"TODO: upgrade jwt-decode when moving to node 18"
|
|
93
93
|
],
|
|
94
|
-
"version": "3.1.0-next.
|
|
94
|
+
"version": "3.1.0-next.7"
|
|
95
95
|
}
|
package/src/media/properties.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable class-methods-use-this */
|
|
1
2
|
import {
|
|
2
3
|
LocalCameraStream,
|
|
3
4
|
LocalMicrophoneStream,
|
|
@@ -182,25 +183,45 @@ export default class MediaProperties {
|
|
|
182
183
|
}
|
|
183
184
|
|
|
184
185
|
/**
|
|
185
|
-
* Returns
|
|
186
|
+
* Returns ICE transport information:
|
|
187
|
+
* - selectedCandidatePairChanges - number of times the selected candidate pair was changed, it should be at least 1 for successful connections
|
|
188
|
+
* it will be -1 if browser doesn't supply this information
|
|
189
|
+
* - numTransports - number of transports (should be 1 if we're using bundle)
|
|
186
190
|
*
|
|
187
|
-
* @
|
|
191
|
+
* @param {Array<any>} allStatsReports array of RTC stats reports
|
|
192
|
+
* @returns {Object}
|
|
188
193
|
*/
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const
|
|
194
|
+
private getTransportInfo(allStatsReports: any[]): {
|
|
195
|
+
selectedCandidatePairChanges: number;
|
|
196
|
+
numTransports: number;
|
|
197
|
+
} {
|
|
198
|
+
const transports = allStatsReports.filter((report) => report.type === 'transport');
|
|
194
199
|
|
|
195
|
-
|
|
196
|
-
const statsResult = await this.webrtcMediaConnection.getStats();
|
|
197
|
-
statsResult.forEach((report) => allStatsReports.push(report));
|
|
198
|
-
} catch (error) {
|
|
200
|
+
if (transports.length > 1) {
|
|
199
201
|
LoggerProxy.logger.warn(
|
|
200
|
-
`Media:properties#
|
|
202
|
+
`Media:properties#getSelectedCandidatePairChanges --> found more than 1 transport: ${transports.length}`
|
|
201
203
|
);
|
|
202
204
|
}
|
|
203
205
|
|
|
206
|
+
return {
|
|
207
|
+
selectedCandidatePairChanges:
|
|
208
|
+
transports.length > 0 && transports[0].selectedCandidatePairChanges !== undefined
|
|
209
|
+
? transports[0].selectedCandidatePairChanges
|
|
210
|
+
: -1,
|
|
211
|
+
numTransports: transports.length,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Returns the type of a connection that has been established
|
|
217
|
+
* It should be 'UDP' | 'TCP' | 'TURN-TLS' | 'TURN-TCP' | 'TURN-UDP' | 'unknown'
|
|
218
|
+
*
|
|
219
|
+
* If connection was not established, it returns 'unknown'
|
|
220
|
+
*
|
|
221
|
+
* @param {Array<any>} allStatsReports array of RTC stats reports
|
|
222
|
+
* @returns {string}
|
|
223
|
+
*/
|
|
224
|
+
private getConnectionType(allStatsReports: any[]) {
|
|
204
225
|
const successfulCandidatePairs = allStatsReports.filter(
|
|
205
226
|
(report) => report.type === 'candidate-pair' && report.state?.toLowerCase() === 'succeeded'
|
|
206
227
|
);
|
|
@@ -215,7 +236,7 @@ export default class MediaProperties {
|
|
|
215
236
|
|
|
216
237
|
if (localCandidate === undefined) {
|
|
217
238
|
LoggerProxy.logger.warn(
|
|
218
|
-
`Media:properties#
|
|
239
|
+
`Media:properties#getConnectionType --> failed to find local candidate "${pair.localCandidateId}" in getStats() results`
|
|
219
240
|
);
|
|
220
241
|
|
|
221
242
|
return false;
|
|
@@ -235,7 +256,7 @@ export default class MediaProperties {
|
|
|
235
256
|
return true;
|
|
236
257
|
}
|
|
237
258
|
LoggerProxy.logger.warn(
|
|
238
|
-
`Media:properties#
|
|
259
|
+
`Media:properties#getConnectionType --> missing localCandidate.protocol, candidateType=${localCandidate.candidateType}`
|
|
239
260
|
);
|
|
240
261
|
|
|
241
262
|
return false;
|
|
@@ -247,7 +268,7 @@ export default class MediaProperties {
|
|
|
247
268
|
.map((report) => report.state);
|
|
248
269
|
|
|
249
270
|
LoggerProxy.logger.warn(
|
|
250
|
-
`Media:properties#
|
|
271
|
+
`Media:properties#getConnectionType --> all candidate pair states: ${JSON.stringify(
|
|
251
272
|
candidatePairStates
|
|
252
273
|
)}`
|
|
253
274
|
);
|
|
@@ -255,4 +276,35 @@ export default class MediaProperties {
|
|
|
255
276
|
|
|
256
277
|
return foundConnectionType;
|
|
257
278
|
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Returns information about current webrtc media connection
|
|
282
|
+
*
|
|
283
|
+
* @returns {Promise<Object>}
|
|
284
|
+
*/
|
|
285
|
+
async getCurrentConnectionInfo(): Promise<{
|
|
286
|
+
connectionType: string;
|
|
287
|
+
selectedCandidatePairChanges: number;
|
|
288
|
+
numTransports: number;
|
|
289
|
+
}> {
|
|
290
|
+
const allStatsReports = [];
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
const statsResult = await this.webrtcMediaConnection.getStats();
|
|
294
|
+
statsResult.forEach((report) => allStatsReports.push(report));
|
|
295
|
+
} catch (error) {
|
|
296
|
+
LoggerProxy.logger.warn(
|
|
297
|
+
`Media:properties#getCurrentConnectionInfo --> getStats() failed: ${error}`
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const connectionType = this.getConnectionType(allStatsReports);
|
|
302
|
+
const {selectedCandidatePairChanges, numTransports} = this.getTransportInfo(allStatsReports);
|
|
303
|
+
|
|
304
|
+
return {
|
|
305
|
+
connectionType,
|
|
306
|
+
selectedCandidatePairChanges,
|
|
307
|
+
numTransports,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
258
310
|
}
|
package/src/meeting/index.ts
CHANGED
|
@@ -678,6 +678,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
678
678
|
private deferSDPAnswer?: Defer; // used for waiting for a response
|
|
679
679
|
private sdpResponseTimer?: ReturnType<typeof setTimeout>;
|
|
680
680
|
private hasMediaConnectionConnectedAtLeastOnce: boolean;
|
|
681
|
+
private joinWithMediaRetryInfo?: {isRetry: boolean; prevJoinResponse?: any};
|
|
681
682
|
|
|
682
683
|
/**
|
|
683
684
|
* @param {Object} attrs
|
|
@@ -1459,6 +1460,15 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1459
1460
|
* @memberof Meeting
|
|
1460
1461
|
*/
|
|
1461
1462
|
this.hasMediaConnectionConnectedAtLeastOnce = false;
|
|
1463
|
+
|
|
1464
|
+
/**
|
|
1465
|
+
* Information needed for a retry of a call to joinWithMedia
|
|
1466
|
+
* @instance
|
|
1467
|
+
* @type {{isRetry: boolean; prevJoinResponse?: any}}
|
|
1468
|
+
* @private
|
|
1469
|
+
* @memberof Meeting
|
|
1470
|
+
*/
|
|
1471
|
+
this.joinWithMediaRetryInfo = {isRetry: false, prevJoinResponse: undefined};
|
|
1462
1472
|
}
|
|
1463
1473
|
|
|
1464
1474
|
/**
|
|
@@ -4527,6 +4537,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4527
4537
|
} = {}
|
|
4528
4538
|
) {
|
|
4529
4539
|
const {mediaOptions, joinOptions = {}} = options;
|
|
4540
|
+
const {isRetry, prevJoinResponse} = this.joinWithMediaRetryInfo;
|
|
4530
4541
|
|
|
4531
4542
|
if (!mediaOptions?.allowMediaInLobby) {
|
|
4532
4543
|
return Promise.reject(
|
|
@@ -4538,6 +4549,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4538
4549
|
LoggerProxy.logger.info('Meeting:index#joinWithMedia called');
|
|
4539
4550
|
|
|
4540
4551
|
let joined = false;
|
|
4552
|
+
let joinResponse = prevJoinResponse;
|
|
4541
4553
|
|
|
4542
4554
|
try {
|
|
4543
4555
|
let turnServerInfo;
|
|
@@ -4550,7 +4562,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4550
4562
|
({turnDiscoverySkippedReason} = turnDiscoveryRequest);
|
|
4551
4563
|
joinOptions.roapMessage = turnDiscoveryRequest.roapMessage;
|
|
4552
4564
|
|
|
4553
|
-
|
|
4565
|
+
if (!joinResponse) {
|
|
4566
|
+
LoggerProxy.logger.info(
|
|
4567
|
+
'Meeting:index#joinWithMedia ---> calling join with joinOptions, ',
|
|
4568
|
+
joinOptions
|
|
4569
|
+
);
|
|
4570
|
+
|
|
4571
|
+
joinResponse = await this.join(joinOptions);
|
|
4572
|
+
}
|
|
4554
4573
|
|
|
4555
4574
|
joined = true;
|
|
4556
4575
|
|
|
@@ -4568,6 +4587,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4568
4587
|
|
|
4569
4588
|
const mediaResponse = await this.addMedia(mediaOptions, turnServerInfo);
|
|
4570
4589
|
|
|
4590
|
+
this.joinWithMediaRetryInfo = {isRetry: false, prevJoinResponse: undefined};
|
|
4591
|
+
|
|
4571
4592
|
return {
|
|
4572
4593
|
join: joinResponse,
|
|
4573
4594
|
media: mediaResponse,
|
|
@@ -4579,7 +4600,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4579
4600
|
|
|
4580
4601
|
this.roap.abortTurnDiscovery();
|
|
4581
4602
|
|
|
4582
|
-
if (joined) {
|
|
4603
|
+
if (joined && isRetry) {
|
|
4583
4604
|
try {
|
|
4584
4605
|
await this.leave({resourceId: joinOptions?.resourceId, reason: 'joinWithMedia failure'});
|
|
4585
4606
|
} catch (e) {
|
|
@@ -4596,12 +4617,23 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4596
4617
|
reason: error.message,
|
|
4597
4618
|
stack: error.stack,
|
|
4598
4619
|
leaveErrorReason: leaveError?.message,
|
|
4620
|
+
isRetry,
|
|
4599
4621
|
},
|
|
4600
4622
|
{
|
|
4601
4623
|
type: error.name,
|
|
4602
4624
|
}
|
|
4603
4625
|
);
|
|
4604
4626
|
|
|
4627
|
+
if (!isRetry) {
|
|
4628
|
+
LoggerProxy.logger.warn('Meeting:index#joinWithMedia --> retrying call to joinWithMedia');
|
|
4629
|
+
this.joinWithMediaRetryInfo.isRetry = true;
|
|
4630
|
+
this.joinWithMediaRetryInfo.prevJoinResponse = joinResponse;
|
|
4631
|
+
|
|
4632
|
+
return this.joinWithMedia(options);
|
|
4633
|
+
}
|
|
4634
|
+
|
|
4635
|
+
this.joinWithMediaRetryInfo = {isRetry: false, prevJoinResponse: undefined};
|
|
4636
|
+
|
|
4605
4637
|
throw error;
|
|
4606
4638
|
}
|
|
4607
4639
|
}
|
|
@@ -6780,7 +6812,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6780
6812
|
await this.enqueueScreenShareFloorRequest();
|
|
6781
6813
|
}
|
|
6782
6814
|
|
|
6783
|
-
const connectionType
|
|
6815
|
+
const {connectionType, selectedCandidatePairChanges, numTransports} =
|
|
6816
|
+
await this.mediaProperties.getCurrentConnectionInfo();
|
|
6784
6817
|
// @ts-ignore
|
|
6785
6818
|
const reachabilityStats = await this.webex.meetings.reachability.getReachabilityMetrics();
|
|
6786
6819
|
|
|
@@ -6788,8 +6821,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6788
6821
|
correlation_id: this.correlationId,
|
|
6789
6822
|
locus_id: this.locusUrl.split('/').pop(),
|
|
6790
6823
|
connectionType,
|
|
6824
|
+
selectedCandidatePairChanges,
|
|
6825
|
+
numTransports,
|
|
6791
6826
|
isMultistream: this.isMultistream,
|
|
6792
6827
|
retriedWithTurnServer: this.retriedWithTurnServer,
|
|
6828
|
+
isJoinWithMediaRetry: this.joinWithMediaRetryInfo.isRetry,
|
|
6793
6829
|
...reachabilityStats,
|
|
6794
6830
|
});
|
|
6795
6831
|
// @ts-ignore
|
|
@@ -6811,16 +6847,22 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6811
6847
|
// @ts-ignore
|
|
6812
6848
|
const reachabilityMetrics = await this.webex.meetings.reachability.getReachabilityMetrics();
|
|
6813
6849
|
|
|
6850
|
+
const {selectedCandidatePairChanges, numTransports} =
|
|
6851
|
+
await this.mediaProperties.getCurrentConnectionInfo();
|
|
6852
|
+
|
|
6814
6853
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE, {
|
|
6815
6854
|
correlation_id: this.correlationId,
|
|
6816
6855
|
locus_id: this.locusUrl.split('/').pop(),
|
|
6817
6856
|
reason: error.message,
|
|
6818
6857
|
stack: error.stack,
|
|
6819
6858
|
code: error.code,
|
|
6859
|
+
selectedCandidatePairChanges,
|
|
6860
|
+
numTransports,
|
|
6820
6861
|
turnDiscoverySkippedReason: this.turnDiscoverySkippedReason,
|
|
6821
6862
|
turnServerUsed: this.turnServerUsed,
|
|
6822
6863
|
retriedWithTurnServer: this.retriedWithTurnServer,
|
|
6823
6864
|
isMultistream: this.isMultistream,
|
|
6865
|
+
isJoinWithMediaRetry: this.joinWithMediaRetryInfo.isRetry,
|
|
6824
6866
|
signalingState:
|
|
6825
6867
|
this.mediaProperties.webrtcMediaConnection?.multistreamConnection?.pc?.pc
|
|
6826
6868
|
?.signalingState ||
|