@webex/plugin-meetings 3.8.0-next.54 → 3.8.0-next.56
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/common/errors/webex-errors.js +12 -2
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/meeting/index.js +85 -42
- package/dist/meeting/index.js.map +1 -1
- package/dist/types/common/errors/webex-errors.d.ts +7 -1
- package/dist/types/meeting/index.d.ts +6 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +3 -3
- package/src/common/errors/webex-errors.ts +8 -1
- package/src/meeting/index.ts +60 -19
- package/test/unit/spec/meeting/index.js +137 -12
@@ -85,9 +85,15 @@ export { IceGatheringFailed };
|
|
85
85
|
* @extends WebexMeetingsError
|
86
86
|
* @property {number} code - 30203
|
87
87
|
* @property {string} message - 'Failed to add media'
|
88
|
+
* @property {Error} [cause] - The underlying error that caused the failure
|
88
89
|
*/
|
89
90
|
declare class AddMediaFailed extends WebexMeetingsError {
|
90
91
|
static CODE: number;
|
91
|
-
|
92
|
+
cause?: Error;
|
93
|
+
/**
|
94
|
+
* Creates a new AddMediaFailed error
|
95
|
+
* @param {Error} [cause] - The underlying error that caused the media addition to fail
|
96
|
+
*/
|
97
|
+
constructor(cause?: Error);
|
92
98
|
}
|
93
99
|
export { AddMediaFailed };
|
@@ -1976,5 +1976,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
1976
1976
|
* @returns {Promise<void>}
|
1977
1977
|
*/
|
1978
1978
|
checkAndRefreshPermissionToken(threshold: number, reason: string): Promise<void>;
|
1979
|
+
/**
|
1980
|
+
* Gets the media reachability metrics
|
1981
|
+
*
|
1982
|
+
* @returns {Promise<MediaReachabilityMetrics>}
|
1983
|
+
*/
|
1984
|
+
private getMediaReachabilityMetricFields;
|
1979
1985
|
}
|
1980
1986
|
export {};
|
package/dist/webinar/index.js
CHANGED
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.8.0-next.
|
46
|
+
"@webex/plugin-meetings": "3.8.0-next.56",
|
47
47
|
"@webex/plugin-rooms": "3.8.0-next.21",
|
48
48
|
"@webex/test-helper-chai": "3.8.0-next.17",
|
49
49
|
"@webex/test-helper-mocha": "3.8.0-next.17",
|
@@ -71,7 +71,7 @@
|
|
71
71
|
"@webex/internal-plugin-metrics": "3.8.0-next.17",
|
72
72
|
"@webex/internal-plugin-support": "3.8.0-next.21",
|
73
73
|
"@webex/internal-plugin-user": "3.8.0-next.17",
|
74
|
-
"@webex/internal-plugin-voicea": "3.8.0-next.
|
74
|
+
"@webex/internal-plugin-voicea": "3.8.0-next.56",
|
75
75
|
"@webex/media-helpers": "3.8.0-next.19",
|
76
76
|
"@webex/plugin-people": "3.8.0-next.19",
|
77
77
|
"@webex/plugin-rooms": "3.8.0-next.21",
|
@@ -92,5 +92,5 @@
|
|
92
92
|
"//": [
|
93
93
|
"TODO: upgrade jwt-decode when moving to node 18"
|
94
94
|
],
|
95
|
-
"version": "3.8.0-next.
|
95
|
+
"version": "3.8.0-next.56"
|
96
96
|
}
|
@@ -152,12 +152,19 @@ WebExMeetingsErrors[IceGatheringFailed.CODE] = IceGatheringFailed;
|
|
152
152
|
* @extends WebexMeetingsError
|
153
153
|
* @property {number} code - 30203
|
154
154
|
* @property {string} message - 'Failed to add media'
|
155
|
+
* @property {Error} [cause] - The underlying error that caused the failure
|
155
156
|
*/
|
156
157
|
class AddMediaFailed extends WebexMeetingsError {
|
157
158
|
static CODE = 30203;
|
159
|
+
cause?: Error;
|
158
160
|
|
159
|
-
|
161
|
+
/**
|
162
|
+
* Creates a new AddMediaFailed error
|
163
|
+
* @param {Error} [cause] - The underlying error that caused the media addition to fail
|
164
|
+
*/
|
165
|
+
constructor(cause?: Error) {
|
160
166
|
super(AddMediaFailed.CODE, 'Failed to add media');
|
167
|
+
this.cause = cause;
|
161
168
|
}
|
162
169
|
}
|
163
170
|
export {AddMediaFailed};
|
package/src/meeting/index.ts
CHANGED
@@ -164,6 +164,7 @@ import Member from '../member';
|
|
164
164
|
import {BrbState, createBrbState} from './brbState';
|
165
165
|
import MultistreamNotSupportedError from '../common/errors/multistream-not-supported-error';
|
166
166
|
import JoinForbiddenError from '../common/errors/join-forbidden-error';
|
167
|
+
import {ReachabilityMetrics} from '../reachability/reachability.types';
|
167
168
|
|
168
169
|
// default callback so we don't call an undefined function, but in practice it should never be used
|
169
170
|
const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL';
|
@@ -262,6 +263,8 @@ type FetchMeetingInfoParams = {
|
|
262
263
|
sendCAevents?: boolean;
|
263
264
|
};
|
264
265
|
|
266
|
+
type MediaReachabilityMetrics = ReachabilityMetrics & {isSubnetReachable: boolean};
|
267
|
+
|
265
268
|
/**
|
266
269
|
* MediaDirection
|
267
270
|
* @typedef {Object} MediaDirection
|
@@ -7159,12 +7162,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7159
7162
|
},
|
7160
7163
|
options: {
|
7161
7164
|
meetingId: this.id,
|
7165
|
+
rawError: error,
|
7162
7166
|
},
|
7163
7167
|
});
|
7164
7168
|
}
|
7165
|
-
|
7169
|
+
|
7170
|
+
const timedOutError = new Error(
|
7166
7171
|
`Timed out waiting for media connection to be connected, correlationId=${this.correlationId}`
|
7167
7172
|
);
|
7173
|
+
|
7174
|
+
timedOutError.cause = error;
|
7175
|
+
|
7176
|
+
throw timedOutError;
|
7168
7177
|
}
|
7169
7178
|
}
|
7170
7179
|
|
@@ -7225,6 +7234,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7225
7234
|
ROAP_OFFER_ANSWER_EXCHANGE_TIMEOUT / 1000
|
7226
7235
|
} seconds`
|
7227
7236
|
);
|
7237
|
+
|
7238
|
+
const error = new Error('Timed out waiting for REMOTE SDP ANSWER');
|
7239
|
+
|
7228
7240
|
// @ts-ignore
|
7229
7241
|
this.webex.internal.newMetrics.submitClientEvent({
|
7230
7242
|
name: 'client.media-engine.remote-sdp-received',
|
@@ -7237,10 +7249,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7237
7249
|
}),
|
7238
7250
|
],
|
7239
7251
|
},
|
7240
|
-
options: {meetingId: this.id, rawError:
|
7252
|
+
options: {meetingId: this.id, rawError: error},
|
7241
7253
|
});
|
7242
7254
|
|
7243
|
-
deferSDPAnswer.reject(
|
7255
|
+
deferSDPAnswer.reject(error);
|
7244
7256
|
}, ROAP_OFFER_ANSWER_EXCHANGE_TIMEOUT);
|
7245
7257
|
|
7246
7258
|
LoggerProxy.logger.info(`${LOG_HEADER} waiting for REMOTE SDP ANSWER...`);
|
@@ -7345,7 +7357,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7345
7357
|
error
|
7346
7358
|
);
|
7347
7359
|
|
7348
|
-
throw new AddMediaFailed();
|
7360
|
+
throw new AddMediaFailed(error);
|
7349
7361
|
}
|
7350
7362
|
}
|
7351
7363
|
|
@@ -7760,14 +7772,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7760
7772
|
|
7761
7773
|
const {connectionType, selectedCandidatePairChanges, numTransports} =
|
7762
7774
|
await this.mediaProperties.getCurrentConnectionInfo();
|
7763
|
-
|
7764
|
-
const reachabilityStats = await this.webex.meetings.reachability.getReachabilityMetrics();
|
7775
|
+
|
7765
7776
|
const iceCandidateErrors = Object.fromEntries(this.iceCandidateErrors);
|
7766
7777
|
|
7767
|
-
|
7768
|
-
const isSubnetReachable = this.webex.meetings.reachability.isSubnetReachable(
|
7769
|
-
this.mediaServerIp
|
7770
|
-
);
|
7778
|
+
const reachabilityMetrics = await this.getMediaReachabilityMetricFields();
|
7771
7779
|
|
7772
7780
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_MEDIA_SUCCESS, {
|
7773
7781
|
correlation_id: this.correlationId,
|
@@ -7778,8 +7786,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7778
7786
|
isMultistream: this.isMultistream,
|
7779
7787
|
retriedWithTurnServer: this.addMediaData.retriedWithTurnServer,
|
7780
7788
|
isJoinWithMediaRetry: this.joinWithMediaRetryInfo.isRetry,
|
7781
|
-
|
7782
|
-
...reachabilityStats,
|
7789
|
+
...reachabilityMetrics,
|
7783
7790
|
...iceCandidateErrors,
|
7784
7791
|
iceCandidatesCount: this.iceCandidatesCount,
|
7785
7792
|
});
|
@@ -7801,18 +7808,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7801
7808
|
LoggerProxy.logger.error(`${LOG_HEADER} failed to establish media connection: `, error);
|
7802
7809
|
|
7803
7810
|
// @ts-ignore
|
7804
|
-
const reachabilityMetrics = await this.
|
7811
|
+
const reachabilityMetrics = await this.getMediaReachabilityMetricFields();
|
7805
7812
|
|
7806
7813
|
const {selectedCandidatePairChanges, numTransports} =
|
7807
7814
|
await this.mediaProperties.getCurrentConnectionInfo();
|
7808
7815
|
|
7809
7816
|
const iceCandidateErrors = Object.fromEntries(this.iceCandidateErrors);
|
7810
7817
|
|
7811
|
-
// @ts-ignore
|
7812
|
-
const isSubnetReachable = this.webex.meetings.reachability.isSubnetReachable(
|
7813
|
-
this.mediaServerIp
|
7814
|
-
);
|
7815
|
-
|
7816
7818
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE, {
|
7817
7819
|
correlation_id: this.correlationId,
|
7818
7820
|
locus_id: this.locusUrl.split('/').pop(),
|
@@ -7842,7 +7844,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7842
7844
|
this.mediaProperties.webrtcMediaConnection?.mediaConnection?.pc?.iceConnectionState ||
|
7843
7845
|
'unknown',
|
7844
7846
|
...reachabilityMetrics,
|
7845
|
-
isSubnetReachable,
|
7846
7847
|
...iceCandidateErrors,
|
7847
7848
|
iceCandidatesCount: this.iceCandidatesCount,
|
7848
7849
|
});
|
@@ -9613,4 +9614,44 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
9613
9614
|
|
9614
9615
|
return Promise.resolve();
|
9615
9616
|
}
|
9617
|
+
|
9618
|
+
/**
|
9619
|
+
* Gets the media reachability metrics
|
9620
|
+
*
|
9621
|
+
* @returns {Promise<MediaReachabilityMetrics>}
|
9622
|
+
*/
|
9623
|
+
private async getMediaReachabilityMetricFields(): Promise<MediaReachabilityMetrics> {
|
9624
|
+
const reachabilityMetrics: ReachabilityMetrics =
|
9625
|
+
// @ts-ignore
|
9626
|
+
await this.webex.meetings.reachability.getReachabilityMetrics();
|
9627
|
+
|
9628
|
+
const successKeys: Array<keyof ReachabilityMetrics> = [
|
9629
|
+
'reachability_public_udp_success',
|
9630
|
+
'reachability_public_tcp_success',
|
9631
|
+
'reachability_public_xtls_success',
|
9632
|
+
'reachability_vmn_udp_success',
|
9633
|
+
'reachability_vmn_tcp_success',
|
9634
|
+
'reachability_vmn_xtls_success',
|
9635
|
+
];
|
9636
|
+
|
9637
|
+
const totalSuccessCases = successKeys.reduce((total, key) => {
|
9638
|
+
const value = reachabilityMetrics[key];
|
9639
|
+
if (typeof value === 'number') {
|
9640
|
+
return total + value;
|
9641
|
+
}
|
9642
|
+
|
9643
|
+
return total;
|
9644
|
+
}, 0);
|
9645
|
+
|
9646
|
+
let isSubnetReachable = null;
|
9647
|
+
if (totalSuccessCases > 0) {
|
9648
|
+
// @ts-ignore
|
9649
|
+
isSubnetReachable = this.webex.meetings.reachability.isSubnetReachable(this.mediaServerIp);
|
9650
|
+
}
|
9651
|
+
|
9652
|
+
return {
|
9653
|
+
...reachabilityMetrics,
|
9654
|
+
isSubnetReachable,
|
9655
|
+
};
|
9656
|
+
}
|
9616
9657
|
}
|
@@ -2166,7 +2166,7 @@ describe('plugin-meetings', () => {
|
|
2166
2166
|
someReachabilityMetric1: 'some value1',
|
2167
2167
|
someReachabilityMetric2: 'some value2',
|
2168
2168
|
selectedCandidatePairChanges: 2,
|
2169
|
-
isSubnetReachable:
|
2169
|
+
isSubnetReachable: null,
|
2170
2170
|
numTransports: 1,
|
2171
2171
|
iceCandidatesCount: 0,
|
2172
2172
|
}
|
@@ -2213,7 +2213,7 @@ describe('plugin-meetings', () => {
|
|
2213
2213
|
signalingState: 'unknown',
|
2214
2214
|
connectionState: 'unknown',
|
2215
2215
|
iceConnectionState: 'unknown',
|
2216
|
-
isSubnetReachable:
|
2216
|
+
isSubnetReachable: null,
|
2217
2217
|
})
|
2218
2218
|
);
|
2219
2219
|
|
@@ -2279,7 +2279,7 @@ describe('plugin-meetings', () => {
|
|
2279
2279
|
selectedCandidatePairChanges: 2,
|
2280
2280
|
numTransports: 1,
|
2281
2281
|
iceCandidatesCount: 0,
|
2282
|
-
isSubnetReachable:
|
2282
|
+
isSubnetReachable: null,
|
2283
2283
|
}
|
2284
2284
|
);
|
2285
2285
|
});
|
@@ -2337,7 +2337,7 @@ describe('plugin-meetings', () => {
|
|
2337
2337
|
signalingState: 'have-local-offer',
|
2338
2338
|
connectionState: 'connecting',
|
2339
2339
|
iceConnectionState: 'checking',
|
2340
|
-
isSubnetReachable:
|
2340
|
+
isSubnetReachable: null,
|
2341
2341
|
})
|
2342
2342
|
);
|
2343
2343
|
|
@@ -2395,7 +2395,7 @@ describe('plugin-meetings', () => {
|
|
2395
2395
|
signalingState: 'have-local-offer',
|
2396
2396
|
connectionState: 'connecting',
|
2397
2397
|
iceConnectionState: 'checking',
|
2398
|
-
isSubnetReachable:
|
2398
|
+
isSubnetReachable: null,
|
2399
2399
|
})
|
2400
2400
|
);
|
2401
2401
|
|
@@ -2731,7 +2731,7 @@ describe('plugin-meetings', () => {
|
|
2731
2731
|
sinon.stub().returns(FAKE_ERROR));
|
2732
2732
|
webex.meetings.reachability = {
|
2733
2733
|
isWebexMediaBackendUnreachable: sinon.stub().resolves(false),
|
2734
|
-
getReachabilityMetrics: sinon.stub().resolves(),
|
2734
|
+
getReachabilityMetrics: sinon.stub().resolves({}),
|
2735
2735
|
stopReachability: sinon.stub(),
|
2736
2736
|
isSubnetReachable: sinon.stub().returns(true),
|
2737
2737
|
};
|
@@ -2762,7 +2762,8 @@ describe('plugin-meetings', () => {
|
|
2762
2762
|
turnDiscoverySkippedReason: undefined,
|
2763
2763
|
});
|
2764
2764
|
meeting.meetingState = 'ACTIVE';
|
2765
|
-
|
2765
|
+
const error = {iceConnected: false}
|
2766
|
+
meeting.mediaProperties.waitForMediaConnectionConnected.rejects(error);
|
2766
2767
|
|
2767
2768
|
const forceRtcMetricsSend = sinon.stub().resolves();
|
2768
2769
|
const closeMediaConnectionStub = sinon.stub();
|
@@ -2780,6 +2781,7 @@ describe('plugin-meetings', () => {
|
|
2780
2781
|
})
|
2781
2782
|
.catch((err) => {
|
2782
2783
|
errorThrown = err;
|
2784
|
+
assert.instanceOf(err.cause, Error);
|
2783
2785
|
assert.instanceOf(err, AddMediaFailed);
|
2784
2786
|
});
|
2785
2787
|
|
@@ -2836,6 +2838,7 @@ describe('plugin-meetings', () => {
|
|
2836
2838
|
},
|
2837
2839
|
options: {
|
2838
2840
|
meetingId: meeting.id,
|
2841
|
+
rawError: error,
|
2839
2842
|
},
|
2840
2843
|
});
|
2841
2844
|
assert.calledWith(webex.internal.newMetrics.submitClientEvent.thirdCall, {
|
@@ -2847,6 +2850,7 @@ describe('plugin-meetings', () => {
|
|
2847
2850
|
},
|
2848
2851
|
options: {
|
2849
2852
|
meetingId: meeting.id,
|
2853
|
+
rawError: error,
|
2850
2854
|
},
|
2851
2855
|
});
|
2852
2856
|
|
@@ -2913,7 +2917,7 @@ describe('plugin-meetings', () => {
|
|
2913
2917
|
selectedCandidatePairChanges: 2,
|
2914
2918
|
numTransports: 1,
|
2915
2919
|
iceCandidatesCount: 0,
|
2916
|
-
isSubnetReachable:
|
2920
|
+
isSubnetReachable: null,
|
2917
2921
|
},
|
2918
2922
|
]);
|
2919
2923
|
|
@@ -2975,10 +2979,13 @@ describe('plugin-meetings', () => {
|
|
2975
2979
|
},
|
2976
2980
|
turnDiscoverySkippedReason: undefined,
|
2977
2981
|
});
|
2982
|
+
|
2983
|
+
const mediaConnectionError = new Error('fake error');
|
2984
|
+
|
2978
2985
|
meeting.mediaProperties.waitForMediaConnectionConnected = sinon
|
2979
2986
|
.stub()
|
2980
2987
|
.onFirstCall()
|
2981
|
-
.rejects()
|
2988
|
+
.rejects(mediaConnectionError)
|
2982
2989
|
.onSecondCall()
|
2983
2990
|
.resolves();
|
2984
2991
|
|
@@ -3047,6 +3054,7 @@ describe('plugin-meetings', () => {
|
|
3047
3054
|
},
|
3048
3055
|
options: {
|
3049
3056
|
meetingId: meeting.id,
|
3057
|
+
rawError: mediaConnectionError,
|
3050
3058
|
},
|
3051
3059
|
});
|
3052
3060
|
assert.calledWith(webex.internal.newMetrics.submitClientEvent.thirdCall, {
|
@@ -3112,7 +3120,7 @@ describe('plugin-meetings', () => {
|
|
3112
3120
|
retriedWithTurnServer: true,
|
3113
3121
|
isJoinWithMediaRetry: false,
|
3114
3122
|
iceCandidatesCount: 0,
|
3115
|
-
isSubnetReachable:
|
3123
|
+
isSubnetReachable: null,
|
3116
3124
|
},
|
3117
3125
|
]);
|
3118
3126
|
meeting.roap.doTurnDiscovery;
|
@@ -3269,7 +3277,7 @@ describe('plugin-meetings', () => {
|
|
3269
3277
|
iceCandidatesCount: 3,
|
3270
3278
|
'701_error': 3,
|
3271
3279
|
'701_turn_host_lookup_received_error': 1,
|
3272
|
-
isSubnetReachable:
|
3280
|
+
isSubnetReachable: null,
|
3273
3281
|
}
|
3274
3282
|
);
|
3275
3283
|
|
@@ -3332,7 +3340,7 @@ describe('plugin-meetings', () => {
|
|
3332
3340
|
iceConnectionState: 'unknown',
|
3333
3341
|
selectedCandidatePairChanges: 2,
|
3334
3342
|
numTransports: 1,
|
3335
|
-
isSubnetReachable:
|
3343
|
+
isSubnetReachable: null,
|
3336
3344
|
iceCandidatesCount: 0,
|
3337
3345
|
}
|
3338
3346
|
);
|
@@ -3394,6 +3402,120 @@ describe('plugin-meetings', () => {
|
|
3394
3402
|
numTransports: 1,
|
3395
3403
|
'701_error': 2,
|
3396
3404
|
'701_turn_host_lookup_received_error': 1,
|
3405
|
+
isSubnetReachable: null,
|
3406
|
+
iceCandidatesCount: 0,
|
3407
|
+
}
|
3408
|
+
);
|
3409
|
+
|
3410
|
+
assert.isOk(errorThrown);
|
3411
|
+
});
|
3412
|
+
|
3413
|
+
it('should send valid isSubnetReachability if media connection success', async () => {
|
3414
|
+
meeting.roap.doTurnDiscovery = sinon.stub().returns({
|
3415
|
+
turnServerInfo: undefined,
|
3416
|
+
turnDiscoverySkippedReason: undefined,
|
3417
|
+
});
|
3418
|
+
meeting.meetingState = 'ACTIVE';
|
3419
|
+
meeting.mediaProperties.waitForMediaConnectionConnected.resolves();
|
3420
|
+
meeting.webex.meetings.reachability = {
|
3421
|
+
getReachabilityMetrics: sinon.stub().resolves({
|
3422
|
+
reachability_public_udp_success: 5,
|
3423
|
+
}),
|
3424
|
+
stopReachability: sinon.stub(),
|
3425
|
+
isSubnetReachable: sinon.stub().returns(false),
|
3426
|
+
};
|
3427
|
+
|
3428
|
+
const forceRtcMetricsSend = sinon.stub().resolves();
|
3429
|
+
const closeMediaConnectionStub = sinon.stub();
|
3430
|
+
Media.createMediaConnection = sinon.stub().returns({
|
3431
|
+
close: closeMediaConnectionStub,
|
3432
|
+
forceRtcMetricsSend,
|
3433
|
+
getConnectionState: sinon.stub().returns(ConnectionState.Connected),
|
3434
|
+
initiateOffer: sinon.stub().resolves({}),
|
3435
|
+
on: sinon.stub(),
|
3436
|
+
});
|
3437
|
+
|
3438
|
+
await meeting
|
3439
|
+
.addMedia({
|
3440
|
+
mediaSettings: {},
|
3441
|
+
});
|
3442
|
+
|
3443
|
+
assert.calledWith(
|
3444
|
+
Metrics.sendBehavioralMetric,
|
3445
|
+
BEHAVIORAL_METRICS.ADD_MEDIA_SUCCESS,
|
3446
|
+
{
|
3447
|
+
correlation_id: meeting.correlationId,
|
3448
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
3449
|
+
connectionType: 'udp',
|
3450
|
+
selectedCandidatePairChanges: 2,
|
3451
|
+
numTransports: 1,
|
3452
|
+
isMultistream: false,
|
3453
|
+
retriedWithTurnServer: false,
|
3454
|
+
isJoinWithMediaRetry: false,
|
3455
|
+
iceCandidatesCount: 0,
|
3456
|
+
reachability_public_udp_success: 5,
|
3457
|
+
isSubnetReachable: false,
|
3458
|
+
}
|
3459
|
+
);
|
3460
|
+
});
|
3461
|
+
|
3462
|
+
it('should send valid isSubnetReachability if media connection fails', async () => {
|
3463
|
+
let errorThrown = undefined;
|
3464
|
+
|
3465
|
+
meeting.roap.doTurnDiscovery = sinon.stub().returns({
|
3466
|
+
turnServerInfo: undefined,
|
3467
|
+
turnDiscoverySkippedReason: undefined,
|
3468
|
+
});
|
3469
|
+
meeting.meetingState = 'ACTIVE';
|
3470
|
+
meeting.mediaProperties.waitForMediaConnectionConnected.rejects({iceConnected: false});
|
3471
|
+
meeting.webex.meetings.reachability = {
|
3472
|
+
getReachabilityMetrics: sinon.stub().resolves({
|
3473
|
+
reachability_public_udp_success: 5,
|
3474
|
+
}),
|
3475
|
+
stopReachability: sinon.stub(),
|
3476
|
+
isSubnetReachable: sinon.stub().returns(true),
|
3477
|
+
};
|
3478
|
+
|
3479
|
+
const forceRtcMetricsSend = sinon.stub().resolves();
|
3480
|
+
const closeMediaConnectionStub = sinon.stub();
|
3481
|
+
Media.createMediaConnection = sinon.stub().returns({
|
3482
|
+
close: closeMediaConnectionStub,
|
3483
|
+
forceRtcMetricsSend,
|
3484
|
+
getConnectionState: sinon.stub().returns(ConnectionState.Connected),
|
3485
|
+
initiateOffer: sinon.stub().resolves({}),
|
3486
|
+
on: sinon.stub(),
|
3487
|
+
});
|
3488
|
+
|
3489
|
+
await meeting
|
3490
|
+
.addMedia({
|
3491
|
+
mediaSettings: {},
|
3492
|
+
})
|
3493
|
+
.catch((err) => {
|
3494
|
+
errorThrown = err;
|
3495
|
+
assert.instanceOf(err, AddMediaFailed);
|
3496
|
+
});
|
3497
|
+
|
3498
|
+
// Check that the only metric sent is ADD_MEDIA_FAILURE
|
3499
|
+
assert.calledOnceWithExactly(
|
3500
|
+
Metrics.sendBehavioralMetric,
|
3501
|
+
BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE,
|
3502
|
+
{
|
3503
|
+
correlation_id: meeting.correlationId,
|
3504
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
3505
|
+
reason: errorThrown.message,
|
3506
|
+
stack: errorThrown.stack,
|
3507
|
+
code: errorThrown.code,
|
3508
|
+
turnDiscoverySkippedReason: undefined,
|
3509
|
+
turnServerUsed: true,
|
3510
|
+
retriedWithTurnServer: false,
|
3511
|
+
isMultistream: false,
|
3512
|
+
isJoinWithMediaRetry: false,
|
3513
|
+
signalingState: 'unknown',
|
3514
|
+
connectionState: 'unknown',
|
3515
|
+
iceConnectionState: 'unknown',
|
3516
|
+
selectedCandidatePairChanges: 2,
|
3517
|
+
numTransports: 1,
|
3518
|
+
reachability_public_udp_success: 5,
|
3397
3519
|
isSubnetReachable: true,
|
3398
3520
|
iceCandidatesCount: 0,
|
3399
3521
|
}
|
@@ -3957,6 +4079,9 @@ describe('plugin-meetings', () => {
|
|
3957
4079
|
},
|
3958
4080
|
options: {
|
3959
4081
|
meetingId: meeting.id,
|
4082
|
+
rawError: {
|
4083
|
+
iceConnected: false,
|
4084
|
+
}
|
3960
4085
|
},
|
3961
4086
|
},
|
3962
4087
|
]);
|