@webex/plugin-meetings 3.10.0-next.16 → 3.10.0-next.18
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/locus-info/index.js +31 -16
- package/dist/locus-info/index.js.map +1 -1
- package/dist/meeting/index.js +22 -7
- package/dist/meeting/index.js.map +1 -1
- package/dist/webinar/index.js +1 -1
- package/package.json +13 -13
- package/src/locus-info/index.ts +28 -7
- package/src/meeting/index.ts +20 -1
- package/test/unit/spec/locus-info/index.js +70 -0
- package/test/unit/spec/meeting/index.js +29 -0
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-rooms": "3.10.0-next.
|
|
46
|
+
"@webex/plugin-rooms": "3.10.0-next.8",
|
|
47
47
|
"@webex/test-helper-chai": "3.10.0-next.1",
|
|
48
48
|
"@webex/test-helper-mocha": "3.10.0-next.1",
|
|
49
49
|
"@webex/test-helper-mock-webex": "3.10.0-next.1",
|
|
@@ -63,20 +63,20 @@
|
|
|
63
63
|
"@webex/common": "3.10.0-next.1",
|
|
64
64
|
"@webex/event-dictionary-ts": "^1.0.1930",
|
|
65
65
|
"@webex/internal-media-core": "2.20.3",
|
|
66
|
-
"@webex/internal-plugin-conversation": "3.10.0-next.
|
|
67
|
-
"@webex/internal-plugin-device": "3.10.0-next.
|
|
68
|
-
"@webex/internal-plugin-llm": "3.10.0-next.
|
|
69
|
-
"@webex/internal-plugin-mercury": "3.10.0-next.
|
|
70
|
-
"@webex/internal-plugin-metrics": "3.10.0-next.
|
|
71
|
-
"@webex/internal-plugin-support": "3.10.0-next.
|
|
72
|
-
"@webex/internal-plugin-user": "3.10.0-next.
|
|
73
|
-
"@webex/internal-plugin-voicea": "3.10.0-next.
|
|
66
|
+
"@webex/internal-plugin-conversation": "3.10.0-next.8",
|
|
67
|
+
"@webex/internal-plugin-device": "3.10.0-next.8",
|
|
68
|
+
"@webex/internal-plugin-llm": "3.10.0-next.8",
|
|
69
|
+
"@webex/internal-plugin-mercury": "3.10.0-next.8",
|
|
70
|
+
"@webex/internal-plugin-metrics": "3.10.0-next.8",
|
|
71
|
+
"@webex/internal-plugin-support": "3.10.0-next.8",
|
|
72
|
+
"@webex/internal-plugin-user": "3.10.0-next.8",
|
|
73
|
+
"@webex/internal-plugin-voicea": "3.10.0-next.10",
|
|
74
74
|
"@webex/media-helpers": "3.10.0-next.3",
|
|
75
|
-
"@webex/plugin-people": "3.10.0-next.
|
|
76
|
-
"@webex/plugin-rooms": "3.10.0-next.
|
|
75
|
+
"@webex/plugin-people": "3.10.0-next.8",
|
|
76
|
+
"@webex/plugin-rooms": "3.10.0-next.8",
|
|
77
77
|
"@webex/ts-sdp": "^1.8.1",
|
|
78
78
|
"@webex/web-capabilities": "^1.7.1",
|
|
79
|
-
"@webex/webex-core": "3.10.0-next.
|
|
79
|
+
"@webex/webex-core": "3.10.0-next.8",
|
|
80
80
|
"ampersand-collection": "^2.0.2",
|
|
81
81
|
"bowser": "^2.11.0",
|
|
82
82
|
"btoa": "^1.2.1",
|
|
@@ -93,5 +93,5 @@
|
|
|
93
93
|
"//": [
|
|
94
94
|
"TODO: upgrade jwt-decode when moving to node 18"
|
|
95
95
|
],
|
|
96
|
-
"version": "3.10.0-next.
|
|
96
|
+
"version": "3.10.0-next.18"
|
|
97
97
|
}
|
package/src/locus-info/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
CALL_REMOVED_REASON,
|
|
19
19
|
RECORDING_STATE,
|
|
20
20
|
Enum,
|
|
21
|
+
SELF_ROLES,
|
|
21
22
|
} from '../constants';
|
|
22
23
|
|
|
23
24
|
import InfoUtils from './infoUtils';
|
|
@@ -512,6 +513,14 @@ export default class LocusInfo extends EventsScope {
|
|
|
512
513
|
updateLocusFromHashTreeObject(object: HashTreeObject, locus: LocusDTO): LocusDTO {
|
|
513
514
|
const type = object.htMeta.elementId.type.toLowerCase();
|
|
514
515
|
|
|
516
|
+
const addParticipantObject = (obj: HashTreeObject) => {
|
|
517
|
+
if (!locus.participants) {
|
|
518
|
+
locus.participants = [];
|
|
519
|
+
}
|
|
520
|
+
locus.participants.push(obj.data);
|
|
521
|
+
this.hashTreeObjectId2ParticipantId.set(obj.htMeta.elementId.id, obj.data.id);
|
|
522
|
+
};
|
|
523
|
+
|
|
515
524
|
switch (type) {
|
|
516
525
|
case ObjectType.locus: {
|
|
517
526
|
if (!object.data) {
|
|
@@ -577,13 +586,7 @@ export default class LocusInfo extends EventsScope {
|
|
|
577
586
|
} ${object.data ? 'updated' : 'removed'} version=${object.htMeta.elementId.version}`
|
|
578
587
|
);
|
|
579
588
|
if (object.data) {
|
|
580
|
-
|
|
581
|
-
locus.participants = [];
|
|
582
|
-
}
|
|
583
|
-
const participantObject = object.data;
|
|
584
|
-
participantObject.htMeta = object.htMeta;
|
|
585
|
-
locus.participants.push(participantObject);
|
|
586
|
-
this.hashTreeObjectId2ParticipantId.set(object.htMeta.elementId.id, participantObject.id);
|
|
589
|
+
addParticipantObject(object);
|
|
587
590
|
} else {
|
|
588
591
|
const participantId = this.hashTreeObjectId2ParticipantId.get(object.htMeta.elementId.id);
|
|
589
592
|
|
|
@@ -610,6 +613,24 @@ export default class LocusInfo extends EventsScope {
|
|
|
610
613
|
);
|
|
611
614
|
const locusDtoKey = ObjectTypeToLocusKeyMap[type];
|
|
612
615
|
locus[locusDtoKey] = object.data;
|
|
616
|
+
|
|
617
|
+
/* Hash tree based webinar attendees don't receive a Participant object for themselves from Locus,
|
|
618
|
+
but a lot of existing code in SDK and web app expects a member object for self to exist,
|
|
619
|
+
so whenever SELF changes for a webinar attendee, we copy it into a participant object.
|
|
620
|
+
We can do it, because SELF has always all the same properties as a participant object.
|
|
621
|
+
*/
|
|
622
|
+
if (
|
|
623
|
+
type === ObjectType.self &&
|
|
624
|
+
locus.info?.isWebinar &&
|
|
625
|
+
object.data.controls?.role?.roles?.find(
|
|
626
|
+
(r) => r.type === SELF_ROLES.ATTENDEE && r.hasRole
|
|
627
|
+
)
|
|
628
|
+
) {
|
|
629
|
+
LoggerProxy.logger.info(
|
|
630
|
+
`Locus-info:index#updateLocusFromHashTreeObject --> webinar attendee: creating participant object from self`
|
|
631
|
+
);
|
|
632
|
+
addParticipantObject(object);
|
|
633
|
+
}
|
|
613
634
|
}
|
|
614
635
|
break;
|
|
615
636
|
default:
|
package/src/meeting/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import uuid from 'uuid';
|
|
2
|
-
import {cloneDeep, isEqual, isEmpty} from 'lodash';
|
|
2
|
+
import {cloneDeep, isEqual, isEmpty, merge} from 'lodash';
|
|
3
3
|
import jwtDecode from 'jwt-decode';
|
|
4
4
|
// @ts-ignore - Fix this
|
|
5
5
|
import {StatelessWebexPlugin} from '@webex/webex-core';
|
|
@@ -50,6 +50,11 @@ import {
|
|
|
50
50
|
type MeetingTranscriptPayload,
|
|
51
51
|
} from '@webex/internal-plugin-voicea';
|
|
52
52
|
|
|
53
|
+
import {
|
|
54
|
+
getBrowserMediaErrorCode,
|
|
55
|
+
isBrowserMediaError,
|
|
56
|
+
isBrowserMediaErrorName,
|
|
57
|
+
} from '@webex/internal-plugin-metrics/src/call-diagnostic/call-diagnostic-metrics.util';
|
|
53
58
|
import {processNewCaptions} from './voicea-meeting';
|
|
54
59
|
|
|
55
60
|
import {
|
|
@@ -5440,6 +5445,20 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5440
5445
|
shouldRetry = false;
|
|
5441
5446
|
}
|
|
5442
5447
|
|
|
5448
|
+
if (CallDiagnosticUtils.isBrowserMediaError(error)) {
|
|
5449
|
+
shouldRetry = false;
|
|
5450
|
+
// eslint-disable-next-line no-ex-assign
|
|
5451
|
+
error = merge({
|
|
5452
|
+
error: {
|
|
5453
|
+
body: {
|
|
5454
|
+
errorCode: CallDiagnosticUtils.getBrowserMediaErrorCode(error),
|
|
5455
|
+
message: error?.message,
|
|
5456
|
+
name: error?.name,
|
|
5457
|
+
},
|
|
5458
|
+
},
|
|
5459
|
+
});
|
|
5460
|
+
}
|
|
5461
|
+
|
|
5443
5462
|
// we only want to call leave if join was successful and this was a retry or we won't be doing any more retries
|
|
5444
5463
|
if (joined && (isRetry || !shouldRetry)) {
|
|
5445
5464
|
try {
|
|
@@ -358,6 +358,76 @@ describe('plugin-meetings', () => {
|
|
|
358
358
|
});
|
|
359
359
|
});
|
|
360
360
|
|
|
361
|
+
it('should process locus update correctly when called with updated SELF (webinar non-attendee)', () => {
|
|
362
|
+
const newSelf = {
|
|
363
|
+
id: 'new-self',
|
|
364
|
+
visibleDataSets: ['dataset1', 'dataset2'],
|
|
365
|
+
controls: {
|
|
366
|
+
role: {
|
|
367
|
+
roles: [
|
|
368
|
+
{type: 'PANELIST', hasRole: true},
|
|
369
|
+
{type: 'ATTENDEE', hasRole: false},
|
|
370
|
+
],
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
};
|
|
374
|
+
locusInfo.info.isWebinar = true;
|
|
375
|
+
|
|
376
|
+
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
377
|
+
locusInfoUpdateCallback(OBJECTS_UPDATED, {
|
|
378
|
+
updatedObjects: [{htMeta: {elementId: {type: 'self'}}, data: newSelf}],
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
// check onDeltaLocus() was called with correctly updated locus info
|
|
382
|
+
// without any participant generated
|
|
383
|
+
assert.calledOnceWithExactly(onDeltaLocusStub, {
|
|
384
|
+
...expectedLocusInfo,
|
|
385
|
+
info: {
|
|
386
|
+
...expectedLocusInfo.info,
|
|
387
|
+
isWebinar: true,
|
|
388
|
+
},
|
|
389
|
+
self: newSelf,
|
|
390
|
+
});
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it('should generate a participant when called with updated SELF for webinar attendee', () => {
|
|
394
|
+
const newSelf = {
|
|
395
|
+
id: 'new-self',
|
|
396
|
+
visibleDataSets: ['dataset1', 'dataset2'],
|
|
397
|
+
controls: {
|
|
398
|
+
role: {
|
|
399
|
+
roles: [
|
|
400
|
+
{type: 'something else - should be ignored', hasRole: true},
|
|
401
|
+
{type: 'ATTENDEE', hasRole: true},
|
|
402
|
+
],
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
locusInfo.info.isWebinar = true;
|
|
408
|
+
|
|
409
|
+
// simulate an update from the HashTreeParser (normally this would be triggered by incoming locus messages)
|
|
410
|
+
locusInfoUpdateCallback(OBJECTS_UPDATED, {
|
|
411
|
+
updatedObjects: [{htMeta: {elementId: {type: 'self'}}, data: newSelf}],
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// check onDeltaLocus() was called with correctly updated locus info
|
|
415
|
+
// that contains a participant created from self
|
|
416
|
+
assert.calledOnceWithExactly(onDeltaLocusStub, {
|
|
417
|
+
...expectedLocusInfo,
|
|
418
|
+
info: {
|
|
419
|
+
...expectedLocusInfo.info,
|
|
420
|
+
isWebinar: true,
|
|
421
|
+
},
|
|
422
|
+
self: newSelf,
|
|
423
|
+
participants: [
|
|
424
|
+
{
|
|
425
|
+
...newSelf,
|
|
426
|
+
},
|
|
427
|
+
],
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
|
|
361
431
|
it('should process locus update correctly when called with updated fullState', () => {
|
|
362
432
|
const newFullState = {
|
|
363
433
|
id: 'new-fullState',
|
|
@@ -1003,6 +1003,35 @@ describe('plugin-meetings', () => {
|
|
|
1003
1003
|
);
|
|
1004
1004
|
});
|
|
1005
1005
|
|
|
1006
|
+
it('should call leave() if addMediaInternal() fails ', async () => {
|
|
1007
|
+
const addMediaError = new Error('fake addMedia error');
|
|
1008
|
+
addMediaError.name = 'TypeError';
|
|
1009
|
+
|
|
1010
|
+
const rejectError = {
|
|
1011
|
+
error: {
|
|
1012
|
+
body: {
|
|
1013
|
+
errorCode: 2729,
|
|
1014
|
+
message: 'fake addMedia error',
|
|
1015
|
+
name: 'TypeError'
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
1019
|
+
meeting.addMediaInternal.rejects(addMediaError);
|
|
1020
|
+
sinon.stub(meeting, 'leave').resolves();
|
|
1021
|
+
|
|
1022
|
+
await assert.isRejected(
|
|
1023
|
+
meeting.joinWithMedia({
|
|
1024
|
+
joinOptions,
|
|
1025
|
+
mediaOptions,
|
|
1026
|
+
}),
|
|
1027
|
+
rejectError
|
|
1028
|
+
);
|
|
1029
|
+
|
|
1030
|
+
assert.calledOnce(meeting.join);
|
|
1031
|
+
assert.calledOnce(meeting.addMediaInternal);
|
|
1032
|
+
assert.calledOnce(Metrics.sendBehavioralMetric);
|
|
1033
|
+
});
|
|
1034
|
+
|
|
1006
1035
|
it('should not call leave() if addMediaInternal() fails the first time and succeeds the second time and should only call join() once', async () => {
|
|
1007
1036
|
const addMediaError = new Error('fake addMedia error');
|
|
1008
1037
|
const leaveStub = sinon.stub(meeting, 'leave');
|