@webex/plugin-meetings 3.8.0-next.46 → 3.8.0-next.48
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/meeting/index.js +61 -59
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +5 -1
- package/dist/meeting/locusMediaRequest.js.map +1 -1
- package/dist/meeting/util.js +17 -0
- package/dist/meeting/util.js.map +1 -1
- package/dist/types/meeting/index.d.ts +2 -2
- package/dist/types/meeting/util.d.ts +6 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +21 -21
- package/src/meeting/index.ts +55 -39
- package/src/meeting/locusMediaRequest.ts +6 -1
- package/src/meeting/util.ts +18 -0
- package/test/unit/spec/meeting/index.js +37 -14
- package/test/unit/spec/meeting/locusMediaRequest.ts +6 -1
- package/test/unit/spec/meeting/utils.js +8 -0
package/src/meeting/index.ts
CHANGED
@@ -5856,16 +5856,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
5856
5856
|
this
|
5857
5857
|
);
|
5858
5858
|
|
5859
|
-
const proxyError =
|
5860
|
-
// eslint-disable-next-line require-jsdoc
|
5861
|
-
get(target, prop) {
|
5862
|
-
if (prop === 'handledBySdk') {
|
5863
|
-
return true;
|
5864
|
-
}
|
5865
|
-
|
5866
|
-
return Reflect.get(target, prop);
|
5867
|
-
},
|
5868
|
-
});
|
5859
|
+
const proxyError = MeetingUtil.markErrorAsHandledBySdk(error);
|
5869
5860
|
|
5870
5861
|
joinFailed(proxyError);
|
5871
5862
|
|
@@ -6254,10 +6245,10 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6254
6245
|
/**
|
6255
6246
|
* Handles ROAP_FAILURE event from the webrtc media connection
|
6256
6247
|
*
|
6257
|
-
* @param {Error}
|
6248
|
+
* @param {Error} roapError
|
6258
6249
|
* @returns {void}
|
6259
6250
|
*/
|
6260
|
-
handleRoapFailure = (
|
6251
|
+
handleRoapFailure = (roapError) => {
|
6261
6252
|
// eslint-disable-next-line @typescript-eslint/no-shadow
|
6262
6253
|
const sendBehavioralMetric = (metricName, error, correlationId) => {
|
6263
6254
|
const data = {
|
@@ -6273,6 +6264,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6273
6264
|
Metrics.sendBehavioralMetric(metricName, data, metadata);
|
6274
6265
|
};
|
6275
6266
|
|
6267
|
+
const error = MeetingUtil.markErrorAsHandledBySdk(roapError);
|
6268
|
+
|
6276
6269
|
if (error instanceof Errors.SdpOfferCreationError) {
|
6277
6270
|
sendBehavioralMetric(BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE, error, this.correlationId);
|
6278
6271
|
|
@@ -6311,7 +6304,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6311
6304
|
clearTimeout(this.sdpResponseTimer);
|
6312
6305
|
this.sdpResponseTimer = undefined;
|
6313
6306
|
|
6314
|
-
this.deferSDPAnswer.reject();
|
6307
|
+
this.deferSDPAnswer.reject(error);
|
6315
6308
|
}
|
6316
6309
|
} else if (error instanceof Errors.SdpError) {
|
6317
6310
|
// this covers also the case of Errors.IceGatheringError which extends Errors.SdpError
|
@@ -6466,7 +6459,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
6466
6459
|
{
|
6467
6460
|
logText: `${LOG_HEADER} Roap Offer`,
|
6468
6461
|
}
|
6469
|
-
).catch((
|
6462
|
+
).catch((originalError) => {
|
6463
|
+
const error = MeetingUtil.markErrorAsHandledBySdk(originalError);
|
6464
|
+
|
6470
6465
|
const multistreamNotSupported = error instanceof MultistreamNotSupportedError;
|
6471
6466
|
|
6472
6467
|
// @ts-ignore
|
@@ -7114,7 +7109,28 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7114
7109
|
} catch (error) {
|
7115
7110
|
const {iceConnected} = error;
|
7116
7111
|
|
7112
|
+
let handledBySdk = false;
|
7113
|
+
|
7117
7114
|
if (!this.hasMediaConnectionConnectedAtLeastOnce) {
|
7115
|
+
const caError =
|
7116
|
+
// @ts-ignore
|
7117
|
+
this.webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode({
|
7118
|
+
clientErrorCode: CallDiagnosticUtils.generateClientErrorCodeForIceFailure({
|
7119
|
+
signalingState:
|
7120
|
+
this.mediaProperties.webrtcMediaConnection?.multistreamConnection?.pc?.pc
|
7121
|
+
?.signalingState ||
|
7122
|
+
this.mediaProperties.webrtcMediaConnection?.mediaConnection?.pc?.signalingState ||
|
7123
|
+
'unknown',
|
7124
|
+
iceConnected,
|
7125
|
+
turnServerUsed: this.turnServerUsed,
|
7126
|
+
unreachable:
|
7127
|
+
// @ts-ignore
|
7128
|
+
await this.webex.meetings.reachability
|
7129
|
+
.isWebexMediaBackendUnreachable()
|
7130
|
+
.catch(() => false),
|
7131
|
+
}),
|
7132
|
+
});
|
7133
|
+
|
7118
7134
|
// Only send CA event for join flow if we haven't successfully connected media yet
|
7119
7135
|
// @ts-ignore
|
7120
7136
|
this.webex.internal.newMetrics.submitClientEvent({
|
@@ -7122,37 +7138,25 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7122
7138
|
payload: {
|
7123
7139
|
canProceed: !this.turnServerUsed, // If we haven't done turn tls retry yet we will proceed with join attempt
|
7124
7140
|
icePhase: this.addMediaData.icePhaseCallback(),
|
7125
|
-
errors: [
|
7126
|
-
// @ts-ignore
|
7127
|
-
this.webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode(
|
7128
|
-
{
|
7129
|
-
clientErrorCode: CallDiagnosticUtils.generateClientErrorCodeForIceFailure({
|
7130
|
-
signalingState:
|
7131
|
-
this.mediaProperties.webrtcMediaConnection?.multistreamConnection?.pc?.pc
|
7132
|
-
?.signalingState ||
|
7133
|
-
this.mediaProperties.webrtcMediaConnection?.mediaConnection?.pc
|
7134
|
-
?.signalingState ||
|
7135
|
-
'unknown',
|
7136
|
-
iceConnected,
|
7137
|
-
turnServerUsed: this.turnServerUsed,
|
7138
|
-
unreachable:
|
7139
|
-
// @ts-ignore
|
7140
|
-
await this.webex.meetings.reachability
|
7141
|
-
.isWebexMediaBackendUnreachable()
|
7142
|
-
.catch(() => false),
|
7143
|
-
}),
|
7144
|
-
}
|
7145
|
-
),
|
7146
|
-
],
|
7141
|
+
errors: [caError],
|
7147
7142
|
},
|
7148
7143
|
options: {
|
7149
7144
|
meetingId: this.id,
|
7150
7145
|
},
|
7151
7146
|
});
|
7147
|
+
|
7148
|
+
handledBySdk = true;
|
7152
7149
|
}
|
7153
|
-
|
7150
|
+
|
7151
|
+
let timedOutError = new Error(
|
7154
7152
|
`Timed out waiting for media connection to be connected, correlationId=${this.correlationId}`
|
7155
7153
|
);
|
7154
|
+
|
7155
|
+
if (handledBySdk) {
|
7156
|
+
timedOutError = MeetingUtil.markErrorAsHandledBySdk(timedOutError);
|
7157
|
+
}
|
7158
|
+
|
7159
|
+
throw timedOutError;
|
7156
7160
|
}
|
7157
7161
|
}
|
7158
7162
|
|
@@ -7213,6 +7217,11 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7213
7217
|
ROAP_OFFER_ANSWER_EXCHANGE_TIMEOUT / 1000
|
7214
7218
|
} seconds`
|
7215
7219
|
);
|
7220
|
+
|
7221
|
+
const timeoutError = new Error('Timeout waiting for SDP answer');
|
7222
|
+
|
7223
|
+
const timeoutErrorProxy = MeetingUtil.markErrorAsHandledBySdk(timeoutError);
|
7224
|
+
|
7216
7225
|
// @ts-ignore
|
7217
7226
|
this.webex.internal.newMetrics.submitClientEvent({
|
7218
7227
|
name: 'client.media-engine.remote-sdp-received',
|
@@ -7225,7 +7234,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7225
7234
|
}),
|
7226
7235
|
],
|
7227
7236
|
},
|
7228
|
-
options: {meetingId: this.id, rawError:
|
7237
|
+
options: {meetingId: this.id, rawError: timeoutErrorProxy},
|
7229
7238
|
});
|
7230
7239
|
|
7231
7240
|
deferSDPAnswer.reject(new Error('Timed out waiting for REMOTE SDP ANSWER'));
|
@@ -7333,7 +7342,14 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
7333
7342
|
error
|
7334
7343
|
);
|
7335
7344
|
|
7336
|
-
|
7345
|
+
let addMediaFailedError = new AddMediaFailed();
|
7346
|
+
|
7347
|
+
// @ts-ignore - handledBySdk is added by a proxy
|
7348
|
+
if (error.handledBySdk) {
|
7349
|
+
addMediaFailedError = MeetingUtil.markErrorAsHandledBySdk(addMediaFailedError);
|
7350
|
+
}
|
7351
|
+
|
7352
|
+
throw addMediaFailedError;
|
7337
7353
|
}
|
7338
7354
|
}
|
7339
7355
|
|
@@ -6,6 +6,7 @@ import {WebexPlugin} from '@webex/webex-core';
|
|
6
6
|
import {MEDIA, HTTP_VERBS, ROAP} from '../constants';
|
7
7
|
import LoggerProxy from '../common/logs/logger-proxy';
|
8
8
|
import {ClientMediaPreferences} from '../reachability/reachability.types';
|
9
|
+
import MeetingUtil from './util';
|
9
10
|
|
10
11
|
export type MediaRequestType = 'RoapMessage' | 'LocalMute';
|
11
12
|
export type RequestResult = any;
|
@@ -263,7 +264,9 @@ export class LocusMediaRequest extends WebexPlugin {
|
|
263
264
|
|
264
265
|
return result;
|
265
266
|
})
|
266
|
-
.catch((
|
267
|
+
.catch((error) => {
|
268
|
+
let e = error;
|
269
|
+
|
267
270
|
if (
|
268
271
|
isRequestAffectingConfluenceState(request) &&
|
269
272
|
this.confluenceState === 'creation in progress'
|
@@ -272,6 +275,8 @@ export class LocusMediaRequest extends WebexPlugin {
|
|
272
275
|
}
|
273
276
|
|
274
277
|
if (request.type === 'RoapMessage') {
|
278
|
+
e = MeetingUtil.markErrorAsHandledBySdk(e);
|
279
|
+
|
275
280
|
// @ts-ignore
|
276
281
|
this.webex.internal.newMetrics.submitClientEvent({
|
277
282
|
name: 'client.locus.media.response',
|
package/src/meeting/util.ts
CHANGED
@@ -812,6 +812,24 @@ const MeetingUtil = {
|
|
812
812
|
},
|
813
813
|
];
|
814
814
|
},
|
815
|
+
|
816
|
+
/**
|
817
|
+
* Creates a proxy object to mark an error as handled by the SDK.
|
818
|
+
* @param {Error} error original error
|
819
|
+
* @returns {Proxy} proxy object with handledBySdk property
|
820
|
+
*/
|
821
|
+
markErrorAsHandledBySdk: (error) => {
|
822
|
+
return new Proxy(error, {
|
823
|
+
// eslint-disable-next-line require-jsdoc
|
824
|
+
get(target, prop) {
|
825
|
+
if (prop === 'handledBySdk') {
|
826
|
+
return true;
|
827
|
+
}
|
828
|
+
|
829
|
+
return Reflect.get(target, prop);
|
830
|
+
},
|
831
|
+
});
|
832
|
+
},
|
815
833
|
};
|
816
834
|
|
817
835
|
export default MeetingUtil;
|
@@ -1011,13 +1011,19 @@ describe('plugin-meetings', () => {
|
|
1011
1011
|
.stub()
|
1012
1012
|
.returns(fakeClientError);
|
1013
1013
|
|
1014
|
-
|
1015
|
-
await assert.isRejected(
|
1016
|
-
meeting.joinWithMedia({
|
1014
|
+
const promise = meeting.joinWithMedia({
|
1017
1015
|
joinOptions,
|
1018
1016
|
mediaOptions,
|
1019
1017
|
})
|
1020
|
-
|
1018
|
+
|
1019
|
+
// call joinWithMedia() - it should fail
|
1020
|
+
await assert.isRejected(promise);
|
1021
|
+
|
1022
|
+
const rejectedError = await promise.catch((error) => error);
|
1023
|
+
|
1024
|
+
// Since the SDK has sent the CA events, we need to mark this error as handled
|
1025
|
+
// so the client doesn't try and send CA events again
|
1026
|
+
assert.isTrue(rejectedError.handledBySdk);
|
1021
1027
|
|
1022
1028
|
// check the right CA events have been sent:
|
1023
1029
|
// calls at index 0 and 2 to submitClientEvent are for "client.media.capabilities" which we don't care about in this test
|
@@ -8810,14 +8816,21 @@ describe('plugin-meetings', () => {
|
|
8810
8816
|
clock.restore();
|
8811
8817
|
});
|
8812
8818
|
|
8813
|
-
const checkMetricSent = (event, error) => {
|
8819
|
+
const checkMetricSent = (event, error, expectedErrorCode) => {
|
8814
8820
|
assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
|
8815
|
-
assert.
|
8821
|
+
assert.deepEqual(webex.internal.newMetrics.submitClientEvent.getCall(0).args[0], {
|
8816
8822
|
name: event,
|
8817
8823
|
payload: {
|
8818
8824
|
canProceed: false,
|
8819
8825
|
},
|
8820
|
-
options: {
|
8826
|
+
options: {
|
8827
|
+
rawError: {
|
8828
|
+
...(error.cause ? {cause: {name: error.cause.name}} : {cause: undefined}),
|
8829
|
+
code: expectedErrorCode,
|
8830
|
+
name: error.name,
|
8831
|
+
},
|
8832
|
+
meetingId: meeting.id,
|
8833
|
+
},
|
8821
8834
|
});
|
8822
8835
|
};
|
8823
8836
|
|
@@ -8851,7 +8864,7 @@ describe('plugin-meetings', () => {
|
|
8851
8864
|
|
8852
8865
|
eventListeners[MediaConnectionEventNames.ROAP_FAILURE](fakeError);
|
8853
8866
|
|
8854
|
-
checkMetricSent('client.media-engine.local-sdp-generated', fakeError);
|
8867
|
+
checkMetricSent('client.media-engine.local-sdp-generated', fakeError, 30005);
|
8855
8868
|
checkBehavioralMetricSent(
|
8856
8869
|
BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE,
|
8857
8870
|
Errors.ErrorCode.SdpOfferCreationError,
|
@@ -8868,7 +8881,7 @@ describe('plugin-meetings', () => {
|
|
8868
8881
|
|
8869
8882
|
eventListeners[MediaConnectionEventNames.ROAP_FAILURE](fakeError);
|
8870
8883
|
|
8871
|
-
checkMetricSent('client.media-engine.remote-sdp-received', fakeError);
|
8884
|
+
checkMetricSent('client.media-engine.remote-sdp-received', fakeError, 30006);
|
8872
8885
|
checkBehavioralMetricSent(
|
8873
8886
|
BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE,
|
8874
8887
|
Errors.ErrorCode.SdpOfferHandlingError,
|
@@ -8892,7 +8905,7 @@ describe('plugin-meetings', () => {
|
|
8892
8905
|
|
8893
8906
|
eventListeners[MediaConnectionEventNames.ROAP_FAILURE](fakeError);
|
8894
8907
|
|
8895
|
-
checkMetricSent('client.media-engine.remote-sdp-received', fakeError);
|
8908
|
+
checkMetricSent('client.media-engine.remote-sdp-received', fakeError, 30004);
|
8896
8909
|
checkBehavioralMetricSent(
|
8897
8910
|
BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE,
|
8898
8911
|
Errors.ErrorCode.SdpAnswerHandlingError,
|
@@ -8900,6 +8913,7 @@ describe('plugin-meetings', () => {
|
|
8900
8913
|
fakeRootCauseName
|
8901
8914
|
);
|
8902
8915
|
assert.calledOnce(meeting.deferSDPAnswer.reject);
|
8916
|
+
assert.isTrue(meeting.deferSDPAnswer.reject.getCall(0).args[0].handledBySdk);
|
8903
8917
|
assert.calledOnce(clearTimeoutSpy);
|
8904
8918
|
});
|
8905
8919
|
|
@@ -8909,7 +8923,7 @@ describe('plugin-meetings', () => {
|
|
8909
8923
|
|
8910
8924
|
eventListeners[MediaConnectionEventNames.ROAP_FAILURE](fakeError);
|
8911
8925
|
|
8912
|
-
checkMetricSent('client.media-engine.local-sdp-generated', fakeError);
|
8926
|
+
checkMetricSent('client.media-engine.local-sdp-generated', fakeError, 30002);
|
8913
8927
|
// expectedMetadataType is the error name in this case
|
8914
8928
|
checkBehavioralMetricSent(
|
8915
8929
|
BEHAVIORAL_METRICS.INVALID_ICE_CANDIDATE,
|
@@ -8927,7 +8941,7 @@ describe('plugin-meetings', () => {
|
|
8927
8941
|
|
8928
8942
|
eventListeners[MediaConnectionEventNames.ROAP_FAILURE](fakeError);
|
8929
8943
|
|
8930
|
-
checkMetricSent('client.media-engine.local-sdp-generated', fakeError);
|
8944
|
+
checkMetricSent('client.media-engine.local-sdp-generated', fakeError, 30003);
|
8931
8945
|
// expectedMetadataType is the error name in this case
|
8932
8946
|
checkBehavioralMetricSent(
|
8933
8947
|
BEHAVIORAL_METRICS.INVALID_ICE_CANDIDATE,
|
@@ -9121,7 +9135,7 @@ describe('plugin-meetings', () => {
|
|
9121
9135
|
assert.calledOnceWithExactly(getErrorPayloadForClientErrorCodeStub, {
|
9122
9136
|
clientErrorCode: expectedErrorCode,
|
9123
9137
|
});
|
9124
|
-
assert.
|
9138
|
+
assert.deepEqual(webex.internal.newMetrics.submitClientEvent.getCall(0).args[0], {
|
9125
9139
|
name: 'client.media-engine.remote-sdp-received',
|
9126
9140
|
payload: {
|
9127
9141
|
canProceed,
|
@@ -9129,9 +9143,18 @@ describe('plugin-meetings', () => {
|
|
9129
9143
|
},
|
9130
9144
|
options: {
|
9131
9145
|
meetingId: meeting.id,
|
9132
|
-
rawError: fakeError
|
9146
|
+
rawError: fakeError instanceof MultistreamNotSupportedError ? {
|
9147
|
+
code: fakeError.code,
|
9148
|
+
name: fakeError.name,
|
9149
|
+
sdkMessage: fakeError.sdkMessage,
|
9150
|
+
error: fakeError.error,
|
9151
|
+
} : {},
|
9133
9152
|
},
|
9134
9153
|
});
|
9154
|
+
const actualError = webex.internal.newMetrics.submitClientEvent.getCall(0).args[0].options.rawError;
|
9155
|
+
|
9156
|
+
assert.isTrue(actualError.handledBySdk);
|
9157
|
+
assert.equal(actualError.message, fakeError.message);
|
9135
9158
|
};
|
9136
9159
|
|
9137
9160
|
it('handles OFFER message correctly when request fails', async () => {
|
@@ -185,7 +185,12 @@ describe('LocusMediaRequest.send()', () => {
|
|
185
185
|
|
186
186
|
it('sends correct metric event when roap message fails', async () => {
|
187
187
|
webexRequestStub.rejects({code: 300, message: 'fake error'});
|
188
|
-
|
188
|
+
|
189
|
+
const promise = sendRoapMessage('OFFER');
|
190
|
+
await assert.isRejected(promise);
|
191
|
+
|
192
|
+
const error = await promise.catch((err) => err);
|
193
|
+
assert.isTrue(error.handledBySdk);
|
189
194
|
|
190
195
|
assert.calledWith(mockWebex.internal.newMetrics.submitClientEvent, {
|
191
196
|
name: 'client.locus.media.response',
|
@@ -1185,6 +1185,14 @@ describe('plugin-meetings', () => {
|
|
1185
1185
|
});
|
1186
1186
|
});
|
1187
1187
|
|
1188
|
+
describe('markErrorAsHandledBySdk', () => {
|
1189
|
+
it('should set the error as handled', () => {
|
1190
|
+
const error = MeetingUtil.markErrorAsHandledBySdk(new Error('Test error'));
|
1191
|
+
|
1192
|
+
assert.isTrue(error.handledBySdk);
|
1193
|
+
})
|
1194
|
+
});
|
1195
|
+
|
1188
1196
|
describe('getChangeMeetingFloorErrorPayload', () => {
|
1189
1197
|
[
|
1190
1198
|
{
|