@webex/plugin-meetings 3.0.0-beta.192 → 3.0.0-beta.194

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.
@@ -37,9 +37,7 @@ import {
37
37
  RemoteTrackType,
38
38
  MediaType,
39
39
  } from '@webex/internal-media-core';
40
- import {
41
- LocalTrackEvents,
42
- } from '@webex/media-helpers';
40
+ import {LocalTrackEvents} from '@webex/media-helpers';
43
41
  import * as StatsAnalyzerModule from '@webex/plugin-meetings/src/statsAnalyzer';
44
42
  import * as MuteStateModule from '@webex/plugin-meetings/src/meeting/muteState';
45
43
  import EventsScope from '@webex/plugin-meetings/src/common/events/events-scope';
@@ -92,7 +90,7 @@ import {
92
90
  MeetingInfoV2PasswordError,
93
91
  MeetingInfoV2PolicyError,
94
92
  } from '../../../../src/meeting-info/meeting-info-v2';
95
- import {ANNOTATION_POLICY} from "../../../../src/annotation/constants";
93
+ import {ANNOTATION_POLICY} from '../../../../src/annotation/constants';
96
94
 
97
95
  // Non-stubbed function
98
96
  const {getDisplayMedia} = Media;
@@ -199,7 +197,7 @@ describe('plugin-meetings', () => {
199
197
  },
200
198
  config: {
201
199
  credentials: {
202
- client_id: 'mock-client-id'
200
+ client_id: 'mock-client-id',
203
201
  },
204
202
  meetings: {
205
203
  reconnection: {
@@ -209,7 +207,7 @@ describe('plugin-meetings', () => {
209
207
  metrics: {},
210
208
  stats: {},
211
209
  experimental: {enableUnifiedMeetings: true},
212
- degradationPreferences: { maxMacroblocksLimit: 8192 },
210
+ degradationPreferences: {maxMacroblocksLimit: 8192},
213
211
  },
214
212
  metrics: {
215
213
  type: ['behavioral'],
@@ -501,7 +499,6 @@ describe('plugin-meetings', () => {
501
499
  });
502
500
 
503
501
  describe('#joinWithMedia', () => {
504
-
505
502
  it('should have #joinWithMedia', () => {
506
503
  assert.exists(meeting.joinWithMedia);
507
504
  });
@@ -590,23 +587,24 @@ describe('plugin-meetings', () => {
590
587
  });
591
588
 
592
589
  describe('#pstnUpdate', () => {
593
-
594
- beforeEach(()=> {
590
+ beforeEach(() => {
595
591
  meeting.locusInfo.self = {state: 'IDLE'};
596
- meeting.dialOutUrl = "dialout:///8167d5ec-40c8-49b8-b49a-8717dbaa7d3a";
597
- })
592
+ meeting.dialOutUrl = 'dialout:///8167d5ec-40c8-49b8-b49a-8717dbaa7d3a';
593
+ });
598
594
 
599
595
  it('checks event MEETING_SELF_PHONE_AUDIO_UPDATE can return reason', () => {
600
596
  const fakePayload = {
601
597
  newSelf: {
602
- pstnDevices: [{
603
- attendeeId: 'test-id',
604
- url: "dialout:///8167d5ec-40c8-49b8-b49a-8717dbaa7d3a",
605
- deviceType: "PROVISIONAL",
606
- state: 'LEFT',
607
- reason: 'FAILURE'
608
- }]
609
- }
598
+ pstnDevices: [
599
+ {
600
+ attendeeId: 'test-id',
601
+ url: 'dialout:///8167d5ec-40c8-49b8-b49a-8717dbaa7d3a',
602
+ deviceType: 'PROVISIONAL',
603
+ state: 'LEFT',
604
+ reason: 'FAILURE',
605
+ },
606
+ ],
607
+ },
610
608
  };
611
609
 
612
610
  meeting.pstnUpdate(fakePayload);
@@ -636,13 +634,15 @@ describe('plugin-meetings', () => {
636
634
  it('checks event MEETING_SELF_PHONE_AUDIO_UPDATE can return undefined reason', () => {
637
635
  const fakePayload = {
638
636
  newSelf: {
639
- pstnDevices: [{
640
- attendeeId: 'test-id',
641
- url: "dialout:///8167d5ec-40c8-49b8-b49a-8717dbaa7d3a",
642
- deviceType: "PROVISIONAL",
643
- state: 'LEFT',
644
- }]
645
- }
637
+ pstnDevices: [
638
+ {
639
+ attendeeId: 'test-id',
640
+ url: 'dialout:///8167d5ec-40c8-49b8-b49a-8717dbaa7d3a',
641
+ deviceType: 'PROVISIONAL',
642
+ state: 'LEFT',
643
+ },
644
+ ],
645
+ },
646
646
  };
647
647
 
648
648
  meeting.pstnUpdate(fakePayload);
@@ -852,9 +852,12 @@ describe('plugin-meetings', () => {
852
852
  assert.calledOnce(meeting.setLocus);
853
853
  assert.equal(result, joinMeetingResult);
854
854
 
855
- assert.calledOnce(webex.internal.newMetrics.submitClientEvent)
855
+ assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
856
856
 
857
- assert.equal(webex.internal.newMetrics.submitClientEvent.getCall(0).args[0].name, 'client.call.initiated');
857
+ assert.equal(
858
+ webex.internal.newMetrics.submitClientEvent.getCall(0).args[0].name,
859
+ 'client.call.initiated'
860
+ );
858
861
  });
859
862
  });
860
863
  describe('failure', () => {
@@ -901,13 +904,20 @@ describe('plugin-meetings', () => {
901
904
 
902
905
  it('should post error event if failed', async () => {
903
906
  await meeting.join().catch(() => {
904
- assert.deepEqual(webex.internal.newMetrics.submitClientEvent.getCall(1).args[0].name, 'client.locus.join.response');
905
- assert.match(webex.internal.newMetrics.submitClientEvent.getCall(1).args[0].options.rawError, {
906
- code: 2,
907
- error: null,
908
- joinOptions: {},
909
- sdkMessage: 'There was an issue joining the meeting, meeting could be in a bad state.'
910
- });
907
+ assert.deepEqual(
908
+ webex.internal.newMetrics.submitClientEvent.getCall(1).args[0].name,
909
+ 'client.locus.join.response'
910
+ );
911
+ assert.match(
912
+ webex.internal.newMetrics.submitClientEvent.getCall(1).args[0].options.rawError,
913
+ {
914
+ code: 2,
915
+ error: null,
916
+ joinOptions: {},
917
+ sdkMessage:
918
+ 'There was an issue joining the meeting, meeting could be in a bad state.',
919
+ }
920
+ );
911
921
  });
912
922
  });
913
923
  it('should fail if password is required', async () => {
@@ -1015,7 +1025,7 @@ describe('plugin-meetings', () => {
1015
1025
  isMultistream: false,
1016
1026
  signalingState: 'unknown',
1017
1027
  connectionState: 'unknown',
1018
- iceConnectionState: 'unknown'
1028
+ iceConnectionState: 'unknown',
1019
1029
  });
1020
1030
  });
1021
1031
 
@@ -1038,7 +1048,7 @@ describe('plugin-meetings', () => {
1038
1048
  isMultistream: false,
1039
1049
  signalingState: 'unknown',
1040
1050
  connectionState: 'unknown',
1041
- iceConnectionState: 'unknown'
1051
+ iceConnectionState: 'unknown',
1042
1052
  });
1043
1053
  });
1044
1054
  });
@@ -1052,7 +1062,6 @@ describe('plugin-meetings', () => {
1052
1062
  });
1053
1063
  const result = await assert.isRejected(meeting.addMedia());
1054
1064
 
1055
-
1056
1065
  assert(Metrics.sendBehavioralMetric.calledOnce);
1057
1066
  assert.calledWith(
1058
1067
  Metrics.sendBehavioralMetric,
@@ -1066,13 +1075,12 @@ describe('plugin-meetings', () => {
1066
1075
  isMultistream: false,
1067
1076
  signalingState: 'unknown',
1068
1077
  connectionState: 'unknown',
1069
- iceConnectionState: 'unknown'
1078
+ iceConnectionState: 'unknown',
1070
1079
  })
1071
1080
  );
1072
1081
 
1073
1082
  assert.instanceOf(result, Error);
1074
1083
  assert.isNull(meeting.mediaProperties.webrtcMediaConnection);
1075
-
1076
1084
  });
1077
1085
 
1078
1086
  it('should include the peer connection properties correctly for multistream', async () => {
@@ -1081,15 +1089,15 @@ describe('plugin-meetings', () => {
1081
1089
  // because some methods (like on() or initiateOffer()) are missing
1082
1090
  Media.createMediaConnection = sinon.stub().returns({
1083
1091
  close: sinon.stub(),
1084
- multistreamConnection :{
1092
+ multistreamConnection: {
1085
1093
  pc: {
1086
1094
  pc: {
1087
1095
  signalingState: 'have-local-offer',
1088
1096
  connectionState: 'connecting',
1089
1097
  iceConnectionState: 'checking',
1090
- }
1091
- }
1092
- }
1098
+ },
1099
+ },
1100
+ },
1093
1101
  });
1094
1102
  // set a statsAnalyzer on the meeting so that we can check that it gets reset to null
1095
1103
  meeting.statsAnalyzer = {stopAnalyzer: sinon.stub().resolves()};
@@ -1109,8 +1117,7 @@ describe('plugin-meetings', () => {
1109
1117
  isMultistream: false,
1110
1118
  signalingState: 'have-local-offer',
1111
1119
  connectionState: 'connecting',
1112
- iceConnectionState: 'checking'
1113
-
1120
+ iceConnectionState: 'checking',
1114
1121
  })
1115
1122
  );
1116
1123
 
@@ -1124,13 +1131,13 @@ describe('plugin-meetings', () => {
1124
1131
  // because some methods (like on() or initiateOffer()) are missing
1125
1132
  Media.createMediaConnection = sinon.stub().returns({
1126
1133
  close: sinon.stub(),
1127
- mediaConnection :{
1134
+ mediaConnection: {
1128
1135
  pc: {
1129
1136
  signalingState: 'have-local-offer',
1130
1137
  connectionState: 'connecting',
1131
1138
  iceConnectionState: 'checking',
1132
- }
1133
- }
1139
+ },
1140
+ },
1134
1141
  });
1135
1142
  // set a statsAnalyzer on the meeting so that we can check that it gets reset to null
1136
1143
  meeting.statsAnalyzer = {stopAnalyzer: sinon.stub().resolves()};
@@ -1150,8 +1157,7 @@ describe('plugin-meetings', () => {
1150
1157
  isMultistream: false,
1151
1158
  signalingState: 'have-local-offer',
1152
1159
  connectionState: 'connecting',
1153
- iceConnectionState: 'checking'
1154
-
1160
+ iceConnectionState: 'checking',
1155
1161
  })
1156
1162
  );
1157
1163
 
@@ -1232,7 +1238,7 @@ describe('plugin-meetings', () => {
1232
1238
  assert.calledOnce(meeting.setMercuryListener);
1233
1239
  assert.calledOnce(fakeMediaConnection.initiateOffer);
1234
1240
  assert.equal(meeting.allowMediaInLobby, allowMediaInLobby);
1235
- }
1241
+ };
1236
1242
 
1237
1243
  it('should attach the media and return promise', async () => {
1238
1244
  meeting.roap.doTurnDiscovery = sinon
@@ -1333,7 +1339,9 @@ describe('plugin-meetings', () => {
1333
1339
  });
1334
1340
 
1335
1341
  it('should reject if waitForMediaConnectionConnected() rejects', async () => {
1336
- webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode = sinon.stub().returns({});
1342
+ webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode = sinon
1343
+ .stub()
1344
+ .returns({});
1337
1345
  meeting.meetingState = 'ACTIVE';
1338
1346
  meeting.mediaProperties.waitForMediaConnectionConnected.rejects(new Error('fake error'));
1339
1347
 
@@ -1375,7 +1383,7 @@ describe('plugin-meetings', () => {
1375
1383
  correlation_id: meeting.correlationId,
1376
1384
  locus_id: meeting.locusUrl.split('/').pop(),
1377
1385
  connectionType: 'udp',
1378
- isMultistream: false
1386
+ isMultistream: false,
1379
1387
  });
1380
1388
 
1381
1389
  assert.called(webex.internal.newMetrics.submitClientEvent);
@@ -1447,7 +1455,7 @@ describe('plugin-meetings', () => {
1447
1455
 
1448
1456
  assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
1449
1457
  name: 'client.media.tx.stop',
1450
- payload: {mediaType:'video'},
1458
+ payload: {mediaType: 'video'},
1451
1459
  options: {
1452
1460
  meetingId: meeting.id,
1453
1461
  },
@@ -1514,8 +1522,8 @@ describe('plugin-meetings', () => {
1514
1522
  networkType: 'wifi',
1515
1523
  },
1516
1524
  payload: {
1517
- intervals: [fakeData]
1518
- }
1525
+ intervals: [fakeData],
1526
+ },
1519
1527
  });
1520
1528
  });
1521
1529
  });
@@ -1567,12 +1575,10 @@ describe('plugin-meetings', () => {
1567
1575
  it('succeeds even if getDevices() throws', async () => {
1568
1576
  meeting.meetingState = 'ACTIVE';
1569
1577
 
1570
- sinon
1571
- .stub(internalMediaModule, 'getDevices')
1572
- .rejects(new Error('fake error'));
1578
+ sinon.stub(internalMediaModule, 'getDevices').rejects(new Error('fake error'));
1573
1579
 
1574
1580
  await meeting.addMedia();
1575
- })
1581
+ });
1576
1582
  });
1577
1583
 
1578
1584
  /* This set of tests are like semi-integration tests, they use real MuteState, Media, LocusMediaRequest and Roap classes.
@@ -1581,186 +1587,195 @@ describe('plugin-meetings', () => {
1581
1587
  to @webex/internal-media-core when addMedia, updateMedia, publishTracks, unpublishTracks are called
1582
1588
  in various combinations.
1583
1589
  */
1584
- [true,false].forEach((isMultistream) =>
1585
- describe(`addMedia/updateMedia semi-integration tests (${isMultistream ? 'multistream' : 'transcoded'})`, () => {
1586
- const webrtcAudioTrack = {
1587
- id: 'underlying audio track',
1588
- getSettings: sinon.stub().returns({deviceId: 'fake device id for audio track'}),
1589
- };
1590
+ [true, false].forEach((isMultistream) =>
1591
+ describe(`addMedia/updateMedia semi-integration tests (${
1592
+ isMultistream ? 'multistream' : 'transcoded'
1593
+ })`, () => {
1594
+ const webrtcAudioTrack = {
1595
+ id: 'underlying audio track',
1596
+ getSettings: sinon.stub().returns({deviceId: 'fake device id for audio track'}),
1597
+ };
1590
1598
 
1591
- let fakeMicrophoneTrack;
1592
- let fakeRoapMediaConnection;
1593
- let fakeMultistreamRoapMediaConnection;
1594
- let roapMediaConnectionConstructorStub;
1595
- let multistreamRoapMediaConnectionConstructorStub;
1596
- let locusMediaRequestStub; // stub for /media requests to Locus
1599
+ let fakeMicrophoneTrack;
1600
+ let fakeRoapMediaConnection;
1601
+ let fakeMultistreamRoapMediaConnection;
1602
+ let roapMediaConnectionConstructorStub;
1603
+ let multistreamRoapMediaConnectionConstructorStub;
1604
+ let locusMediaRequestStub; // stub for /media requests to Locus
1597
1605
 
1598
- const roapOfferMessage = {messageType: 'OFFER', sdp: 'sdp', seq: '1', tieBreaker: '123'};
1606
+ const roapOfferMessage = {messageType: 'OFFER', sdp: 'sdp', seq: '1', tieBreaker: '123'};
1599
1607
 
1600
- let expectedMediaConnectionConfig;
1601
- let expectedDebugId;
1608
+ let expectedMediaConnectionConfig;
1609
+ let expectedDebugId;
1602
1610
 
1603
- let clock;
1611
+ let clock;
1604
1612
 
1605
- beforeEach(() => {
1606
- clock = sinon.useFakeTimers();
1613
+ beforeEach(() => {
1614
+ clock = sinon.useFakeTimers();
1607
1615
 
1608
- meeting.deviceUrl = 'deviceUrl';
1609
- meeting.config.deviceType = 'web';
1610
- meeting.isMultistream = isMultistream;
1611
- meeting.meetingState = 'ACTIVE';
1612
- meeting.mediaId = 'fake media id';
1613
- meeting.selfUrl = 'selfUrl';
1614
- meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().resolves();
1615
- meeting.mediaProperties.getCurrentConnectionType = sinon.stub().resolves('udp');
1616
- meeting.setMercuryListener = sinon.stub();
1617
- meeting.locusInfo.onFullLocus = sinon.stub();
1618
- meeting.webex.meetings.reachability = {
1619
- isAnyClusterReachable: sinon.stub().resolves(true),
1620
- };
1621
- meeting.roap.doTurnDiscovery = sinon
1622
- .stub()
1623
- .resolves({turnServerInfo: {}, turnDiscoverySkippedReason: 'reachability'});
1624
-
1625
- StaticConfig.set({bandwidth: {audio: 1234, video: 5678, startBitrate: 9876}});
1626
-
1627
- // setup things that are expected to be the same across all the tests and are actually irrelevant for these tests
1628
- expectedDebugId = `MC-${meeting.id.substring(0, 4)}`;
1629
- expectedMediaConnectionConfig = {
1630
- iceServers: [ { urls: undefined, username: '', credential: '' } ],
1631
- skipInactiveTransceivers: false,
1632
- requireH264: true,
1633
- sdpMunging: {
1634
- convertPort9to0: false,
1635
- addContentSlides: true,
1636
- bandwidthLimits: {
1637
- audio: StaticConfig.meetings.bandwidth.audio,
1638
- video: StaticConfig.meetings.bandwidth.video,
1616
+ meeting.deviceUrl = 'deviceUrl';
1617
+ meeting.config.deviceType = 'web';
1618
+ meeting.isMultistream = isMultistream;
1619
+ meeting.meetingState = 'ACTIVE';
1620
+ meeting.mediaId = 'fake media id';
1621
+ meeting.selfUrl = 'selfUrl';
1622
+ meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().resolves();
1623
+ meeting.mediaProperties.getCurrentConnectionType = sinon.stub().resolves('udp');
1624
+ meeting.setMercuryListener = sinon.stub();
1625
+ meeting.locusInfo.onFullLocus = sinon.stub();
1626
+ meeting.webex.meetings.reachability = {
1627
+ isAnyClusterReachable: sinon.stub().resolves(true),
1628
+ };
1629
+ meeting.roap.doTurnDiscovery = sinon
1630
+ .stub()
1631
+ .resolves({turnServerInfo: {}, turnDiscoverySkippedReason: 'reachability'});
1632
+
1633
+ StaticConfig.set({bandwidth: {audio: 1234, video: 5678, startBitrate: 9876}});
1634
+
1635
+ // setup things that are expected to be the same across all the tests and are actually irrelevant for these tests
1636
+ expectedDebugId = `MC-${meeting.id.substring(0, 4)}`;
1637
+ expectedMediaConnectionConfig = {
1638
+ iceServers: [{urls: undefined, username: '', credential: ''}],
1639
+ skipInactiveTransceivers: false,
1640
+ requireH264: true,
1641
+ sdpMunging: {
1642
+ convertPort9to0: false,
1643
+ addContentSlides: true,
1644
+ bandwidthLimits: {
1645
+ audio: StaticConfig.meetings.bandwidth.audio,
1646
+ video: StaticConfig.meetings.bandwidth.video,
1647
+ },
1648
+ startBitrate: StaticConfig.meetings.bandwidth.startBitrate,
1649
+ periodicKeyframes: 20,
1650
+ disableExtmap: !meeting.config.enableExtmap,
1651
+ disableRtx: !meeting.config.enableRtx,
1639
1652
  },
1640
- startBitrate: StaticConfig.meetings.bandwidth.startBitrate,
1641
- periodicKeyframes: 20,
1642
- disableExtmap: !meeting.config.enableExtmap,
1643
- disableRtx: !meeting.config.enableRtx,
1644
- },
1645
- };
1653
+ };
1646
1654
 
1647
- // setup stubs
1648
- fakeMicrophoneTrack = {
1649
- id: 'fake mic',
1650
- on: sinon.stub(),
1651
- off: sinon.stub(),
1652
- setUnmuteAllowed: sinon.stub(),
1653
- setMuted: sinon.stub(),
1654
- setPublished: sinon.stub(),
1655
- muted: false,
1656
- underlyingTrack: webrtcAudioTrack
1657
- };
1655
+ // setup stubs
1656
+ fakeMicrophoneTrack = {
1657
+ id: 'fake mic',
1658
+ on: sinon.stub(),
1659
+ off: sinon.stub(),
1660
+ setUnmuteAllowed: sinon.stub(),
1661
+ setMuted: sinon.stub(),
1662
+ setPublished: sinon.stub(),
1663
+ muted: false,
1664
+ underlyingTrack: webrtcAudioTrack,
1665
+ };
1658
1666
 
1659
- fakeRoapMediaConnection = {
1660
- id: 'roap media connection',
1661
- close: sinon.stub(),
1662
- getConnectionState: sinon.stub().returns(ConnectionState.Connected),
1663
- initiateOffer: sinon.stub().resolves({}),
1664
- update: sinon.stub().resolves({}),
1665
- on: sinon.stub(),
1666
- };
1667
+ fakeRoapMediaConnection = {
1668
+ id: 'roap media connection',
1669
+ close: sinon.stub(),
1670
+ getConnectionState: sinon.stub().returns(ConnectionState.Connected),
1671
+ initiateOffer: sinon.stub().resolves({}),
1672
+ update: sinon.stub().resolves({}),
1673
+ on: sinon.stub(),
1674
+ };
1667
1675
 
1668
- fakeMultistreamRoapMediaConnection = {
1669
- id: 'multistream roap media connection',
1670
- close: sinon.stub(),
1671
- getConnectionState: sinon.stub().returns(ConnectionState.Connected),
1672
- initiateOffer: sinon.stub().resolves({}),
1673
- publishTrack: sinon.stub().resolves({}),
1674
- unpublishTrack: sinon.stub().resolves({}),
1675
- on: sinon.stub(),
1676
- requestMedia: sinon.stub(),
1677
- createReceiveSlot: sinon.stub().resolves({on: sinon.stub()}),
1678
- enableMultistreamAudio: sinon.stub(),
1679
- };
1676
+ fakeMultistreamRoapMediaConnection = {
1677
+ id: 'multistream roap media connection',
1678
+ close: sinon.stub(),
1679
+ getConnectionState: sinon.stub().returns(ConnectionState.Connected),
1680
+ initiateOffer: sinon.stub().resolves({}),
1681
+ publishTrack: sinon.stub().resolves({}),
1682
+ unpublishTrack: sinon.stub().resolves({}),
1683
+ on: sinon.stub(),
1684
+ requestMedia: sinon.stub(),
1685
+ createReceiveSlot: sinon.stub().resolves({on: sinon.stub()}),
1686
+ enableMultistreamAudio: sinon.stub(),
1687
+ };
1680
1688
 
1681
- roapMediaConnectionConstructorStub = sinon
1682
- .stub(internalMediaModule, 'RoapMediaConnection')
1683
- .returns(fakeRoapMediaConnection);
1689
+ roapMediaConnectionConstructorStub = sinon
1690
+ .stub(internalMediaModule, 'RoapMediaConnection')
1691
+ .returns(fakeRoapMediaConnection);
1684
1692
 
1685
- multistreamRoapMediaConnectionConstructorStub = sinon
1686
- .stub(internalMediaModule, 'MultistreamRoapMediaConnection')
1687
- .returns(fakeMultistreamRoapMediaConnection);
1693
+ multistreamRoapMediaConnectionConstructorStub = sinon
1694
+ .stub(internalMediaModule, 'MultistreamRoapMediaConnection')
1695
+ .returns(fakeMultistreamRoapMediaConnection);
1688
1696
 
1689
- locusMediaRequestStub = sinon.stub(WebexPlugin.prototype, 'request').resolves({body: {locus: { fullState: {}}}});
1690
- });
1697
+ locusMediaRequestStub = sinon
1698
+ .stub(WebexPlugin.prototype, 'request')
1699
+ .resolves({body: {locus: {fullState: {}}}});
1700
+ });
1691
1701
 
1692
- afterEach(() => {
1693
- clock.restore();
1694
- });
1702
+ afterEach(() => {
1703
+ clock.restore();
1704
+ });
1695
1705
 
1696
- // helper function that waits until all promises are resolved and any queued up /media requests to Locus are sent out
1697
- const stableState = async () => {
1698
- await testUtils.flushPromises();
1699
- clock.tick(1); // needed because LocusMediaRequest uses Lodash.defer()
1700
- }
1706
+ // helper function that waits until all promises are resolved and any queued up /media requests to Locus are sent out
1707
+ const stableState = async () => {
1708
+ await testUtils.flushPromises();
1709
+ clock.tick(1); // needed because LocusMediaRequest uses Lodash.defer()
1710
+ };
1701
1711
 
1702
- const resetHistory = () => {
1703
- locusMediaRequestStub.resetHistory();
1704
- fakeRoapMediaConnection.update.resetHistory();
1705
- fakeMultistreamRoapMediaConnection.publishTrack.resetHistory();
1706
- fakeMultistreamRoapMediaConnection.unpublishTrack.resetHistory();
1707
- };
1712
+ const resetHistory = () => {
1713
+ locusMediaRequestStub.resetHistory();
1714
+ fakeRoapMediaConnection.update.resetHistory();
1715
+ fakeMultistreamRoapMediaConnection.publishTrack.resetHistory();
1716
+ fakeMultistreamRoapMediaConnection.unpublishTrack.resetHistory();
1717
+ };
1708
1718
 
1709
- const getRoapListener = () => {
1710
- const roapMediaConnectionToCheck = isMultistream ? fakeMultistreamRoapMediaConnection : fakeRoapMediaConnection;
1719
+ const getRoapListener = () => {
1720
+ const roapMediaConnectionToCheck = isMultistream
1721
+ ? fakeMultistreamRoapMediaConnection
1722
+ : fakeRoapMediaConnection;
1711
1723
 
1712
- for(let idx = 0; idx < roapMediaConnectionToCheck.on.callCount; idx+= 1) {
1713
- if (roapMediaConnectionToCheck.on.getCall(idx).args[0] === Event.ROAP_MESSAGE_TO_SEND) {
1714
- return roapMediaConnectionToCheck.on.getCall(idx).args[1];
1724
+ for (let idx = 0; idx < roapMediaConnectionToCheck.on.callCount; idx += 1) {
1725
+ if (
1726
+ roapMediaConnectionToCheck.on.getCall(idx).args[0] === Event.ROAP_MESSAGE_TO_SEND
1727
+ ) {
1728
+ return roapMediaConnectionToCheck.on.getCall(idx).args[1];
1729
+ }
1715
1730
  }
1716
- }
1717
- assert.fail('listener for "roap:messageToSend" (Event.ROAP_MESSAGE_TO_SEND) was not registered')
1718
- }
1731
+ assert.fail(
1732
+ 'listener for "roap:messageToSend" (Event.ROAP_MESSAGE_TO_SEND) was not registered'
1733
+ );
1734
+ };
1719
1735
 
1720
- // simulates a Roap offer being generated by the RoapMediaConnection
1721
- const simulateRoapOffer = async () => {
1722
- const roapListener = getRoapListener();
1736
+ // simulates a Roap offer being generated by the RoapMediaConnection
1737
+ const simulateRoapOffer = async () => {
1738
+ const roapListener = getRoapListener();
1723
1739
 
1724
- await roapListener({roapMessage: roapOfferMessage});
1725
- await stableState();
1726
- }
1740
+ await roapListener({roapMessage: roapOfferMessage});
1741
+ await stableState();
1742
+ };
1727
1743
 
1728
- const checkSdpOfferSent = ({audioMuted, videoMuted}) => {
1729
- const {sdp, seq, tieBreaker} = roapOfferMessage;
1744
+ const checkSdpOfferSent = ({audioMuted, videoMuted}) => {
1745
+ const {sdp, seq, tieBreaker} = roapOfferMessage;
1730
1746
 
1731
- assert.calledWith(locusMediaRequestStub,
1732
- {
1747
+ assert.calledWith(locusMediaRequestStub, {
1733
1748
  method: 'PUT',
1734
1749
  uri: `${meeting.selfUrl}/media`,
1735
1750
  body: {
1736
- device: { url: meeting.deviceUrl, deviceType: meeting.config.deviceType },
1751
+ device: {url: meeting.deviceUrl, deviceType: meeting.config.deviceType},
1737
1752
  correlationId: meeting.correlationId,
1738
1753
  localMedias: [
1739
1754
  {
1740
1755
  localSdp: `{"audioMuted":${audioMuted},"videoMuted":${videoMuted},"roapMessage":{"messageType":"OFFER","sdps":["${sdp}"],"version":"2","seq":"${seq}","tieBreaker":"${tieBreaker}"}}`,
1741
- mediaId: 'fake media id'
1742
- }
1756
+ mediaId: 'fake media id',
1757
+ },
1743
1758
  ],
1744
1759
  clientMediaPreferences: {
1745
1760
  preferTranscoding: !meeting.isMultistream,
1746
- joinCookie: undefined
1747
- }
1761
+ joinCookie: undefined,
1762
+ },
1748
1763
  },
1749
1764
  });
1750
- };
1765
+ };
1751
1766
 
1752
- const checkLocalMuteSentToLocus = ({audioMuted, videoMuted}) => {
1753
- assert.calledWith(locusMediaRequestStub, {
1767
+ const checkLocalMuteSentToLocus = ({audioMuted, videoMuted}) => {
1768
+ assert.calledWith(locusMediaRequestStub, {
1754
1769
  method: 'PUT',
1755
1770
  uri: `${meeting.selfUrl}/media`,
1756
1771
  body: {
1757
- device: { url: meeting.deviceUrl, deviceType: meeting.config.deviceType },
1772
+ device: {url: meeting.deviceUrl, deviceType: meeting.config.deviceType},
1758
1773
  correlationId: meeting.correlationId,
1759
1774
  localMedias: [
1760
1775
  {
1761
1776
  localSdp: `{"audioMuted":${audioMuted},"videoMuted":${videoMuted}}`,
1762
- mediaId: 'fake media id'
1763
- }
1777
+ mediaId: 'fake media id',
1778
+ },
1764
1779
  ],
1765
1780
  clientMediaPreferences: {
1766
1781
  preferTranscoding: !meeting.isMultistream,
@@ -1769,197 +1784,221 @@ describe('plugin-meetings', () => {
1769
1784
  usingResource: null,
1770
1785
  },
1771
1786
  });
1772
- };
1787
+ };
1773
1788
 
1774
- const checkMediaConnectionCreated = ({mediaConnectionConfig, localTracks, direction, remoteQualityLevel, expectedDebugId, meetingId}) => {
1775
- if (isMultistream) {
1776
- const {iceServers} = mediaConnectionConfig;
1789
+ const checkMediaConnectionCreated = ({
1790
+ mediaConnectionConfig,
1791
+ localTracks,
1792
+ direction,
1793
+ remoteQualityLevel,
1794
+ expectedDebugId,
1795
+ meetingId,
1796
+ }) => {
1797
+ if (isMultistream) {
1798
+ const {iceServers} = mediaConnectionConfig;
1777
1799
 
1778
- assert.calledOnceWithMatch(multistreamRoapMediaConnectionConstructorStub, {
1779
- iceServers,
1780
- enableMainAudio: direction.audio !== 'inactive',
1781
- enableMainVideo: true
1782
- }, meetingId);
1800
+ assert.calledOnceWithMatch(
1801
+ multistreamRoapMediaConnectionConstructorStub,
1802
+ {
1803
+ iceServers,
1804
+ enableMainAudio: direction.audio !== 'inactive',
1805
+ enableMainVideo: true,
1806
+ },
1807
+ meetingId
1808
+ );
1783
1809
 
1784
- Object.values(localTracks).forEach((track) => {
1785
- if (track) {
1786
- assert.calledOnceWithExactly(fakeMultistreamRoapMediaConnection.publishTrack, track);
1787
- }
1788
- })
1789
- } else {
1790
- assert.calledOnceWithExactly(roapMediaConnectionConstructorStub, mediaConnectionConfig,
1791
- {
1792
- localTracks: {
1793
- audio: localTracks.audio?.underlyingTrack,
1794
- video: localTracks.video?.underlyingTrack,
1795
- screenShareVideo: localTracks.screenShareVideo?.underlyingTrack,
1810
+ Object.values(localTracks).forEach((track) => {
1811
+ if (track) {
1812
+ assert.calledOnceWithExactly(
1813
+ fakeMultistreamRoapMediaConnection.publishTrack,
1814
+ track
1815
+ );
1816
+ }
1817
+ });
1818
+ } else {
1819
+ assert.calledOnceWithExactly(
1820
+ roapMediaConnectionConstructorStub,
1821
+ mediaConnectionConfig,
1822
+ {
1823
+ localTracks: {
1824
+ audio: localTracks.audio?.underlyingTrack,
1825
+ video: localTracks.video?.underlyingTrack,
1826
+ screenShareVideo: localTracks.screenShareVideo?.underlyingTrack,
1827
+ },
1828
+ direction,
1829
+ remoteQualityLevel,
1796
1830
  },
1797
- direction,
1798
- remoteQualityLevel,
1831
+ expectedDebugId
1832
+ );
1833
+ }
1834
+ };
1835
+
1836
+ it('addMedia() works correctly when media is enabled without tracks to publish', async () => {
1837
+ await meeting.addMedia();
1838
+ await simulateRoapOffer();
1839
+
1840
+ // check RoapMediaConnection was created correctly
1841
+ checkMediaConnectionCreated({
1842
+ mediaConnectionConfig: expectedMediaConnectionConfig,
1843
+ localTracks: {
1844
+ audio: undefined,
1845
+ video: undefined,
1846
+ screenShareVideo: undefined,
1847
+ screenShareAudio: undefined,
1799
1848
  },
1800
- expectedDebugId);
1801
- }
1802
- }
1849
+ direction: {
1850
+ audio: 'sendrecv',
1851
+ video: 'sendrecv',
1852
+ screenShareVideo: 'recvonly',
1853
+ },
1854
+ remoteQualityLevel: 'HIGH',
1855
+ expectedDebugId,
1856
+ meetingId: meeting.id,
1857
+ });
1803
1858
 
1804
- it('addMedia() works correctly when media is enabled without tracks to publish', async () => {
1805
- await meeting.addMedia();
1806
- await simulateRoapOffer();
1859
+ // and SDP offer was sent with the right audioMuted/videoMuted values
1860
+ checkSdpOfferSent({audioMuted: true, videoMuted: true});
1807
1861
 
1808
- // check RoapMediaConnection was created correctly
1809
- checkMediaConnectionCreated({
1810
- mediaConnectionConfig: expectedMediaConnectionConfig,
1811
- localTracks: {
1812
- audio: undefined,
1813
- video: undefined,
1814
- screenShareVideo: undefined,
1815
- screenShareAudio: undefined,
1816
- },
1817
- direction: {
1818
- audio: 'sendrecv',
1819
- video: 'sendrecv',
1820
- screenShareVideo: 'recvonly',
1821
- },
1822
- remoteQualityLevel: 'HIGH',
1823
- expectedDebugId,
1824
- meetingId: meeting.id
1862
+ // and that it was the only /media request that was sent
1863
+ assert.calledOnce(locusMediaRequestStub);
1825
1864
  });
1826
1865
 
1827
- // and SDP offer was sent with the right audioMuted/videoMuted values
1828
- checkSdpOfferSent({audioMuted: true, videoMuted: true});
1866
+ it('addMedia() works correctly when media is enabled with tracks to publish', async () => {
1867
+ await meeting.addMedia({localTracks: {microphone: fakeMicrophoneTrack}});
1868
+ await simulateRoapOffer();
1829
1869
 
1830
- // and that it was the only /media request that was sent
1831
- assert.calledOnce(locusMediaRequestStub);
1832
- });
1870
+ // check RoapMediaConnection was created correctly
1871
+ checkMediaConnectionCreated({
1872
+ mediaConnectionConfig: expectedMediaConnectionConfig,
1873
+ localTracks: {
1874
+ audio: fakeMicrophoneTrack,
1875
+ video: undefined,
1876
+ screenShareVideo: undefined,
1877
+ screenShareAudio: undefined,
1878
+ },
1879
+ direction: {
1880
+ audio: 'sendrecv',
1881
+ video: 'sendrecv',
1882
+ screenShareVideo: 'recvonly',
1883
+ },
1884
+ remoteQualityLevel: 'HIGH',
1885
+ expectedDebugId,
1886
+ meetingId: meeting.id,
1887
+ });
1833
1888
 
1834
- it('addMedia() works correctly when media is enabled with tracks to publish', async () => {
1835
- await meeting.addMedia({localTracks: {microphone: fakeMicrophoneTrack}});
1836
- await simulateRoapOffer();
1889
+ // and SDP offer was sent with the right audioMuted/videoMuted values
1890
+ checkSdpOfferSent({audioMuted: false, videoMuted: true});
1837
1891
 
1838
- // check RoapMediaConnection was created correctly
1839
- checkMediaConnectionCreated({
1840
- mediaConnectionConfig: expectedMediaConnectionConfig,
1841
- localTracks: {
1842
- audio: fakeMicrophoneTrack,
1843
- video: undefined,
1844
- screenShareVideo: undefined,
1845
- screenShareAudio: undefined,
1846
- },
1847
- direction: {
1848
- audio: 'sendrecv',
1849
- video: 'sendrecv',
1850
- screenShareVideo: 'recvonly',
1851
- },
1852
- remoteQualityLevel: 'HIGH',
1853
- expectedDebugId,
1854
- meetingId: meeting.id
1892
+ // and no other local mute requests were sent to Locus
1893
+ assert.calledOnce(locusMediaRequestStub);
1855
1894
  });
1856
1895
 
1857
- // and SDP offer was sent with the right audioMuted/videoMuted values
1858
- checkSdpOfferSent({audioMuted: false, videoMuted: true});
1896
+ it('addMedia() works correctly when media is enabled with tracks to publish and track is muted', async () => {
1897
+ fakeMicrophoneTrack.muted = true;
1859
1898
 
1860
- // and no other local mute requests were sent to Locus
1861
- assert.calledOnce(locusMediaRequestStub);
1862
- });
1899
+ await meeting.addMedia({localTracks: {microphone: fakeMicrophoneTrack}});
1900
+ await simulateRoapOffer();
1863
1901
 
1864
- it('addMedia() works correctly when media is enabled with tracks to publish and track is muted', async () => {
1865
- fakeMicrophoneTrack.muted = true;
1902
+ // check RoapMediaConnection was created correctly
1903
+ checkMediaConnectionCreated({
1904
+ mediaConnectionConfig: expectedMediaConnectionConfig,
1905
+ localTracks: {
1906
+ audio: fakeMicrophoneTrack,
1907
+ video: undefined,
1908
+ screenShareVideo: undefined,
1909
+ screenShareAudio: undefined,
1910
+ },
1911
+ direction: {
1912
+ audio: 'sendrecv',
1913
+ video: 'sendrecv',
1914
+ screenShareVideo: 'recvonly',
1915
+ },
1916
+ remoteQualityLevel: 'HIGH',
1917
+ expectedDebugId,
1918
+ meetingId: meeting.id,
1919
+ });
1866
1920
 
1867
- await meeting.addMedia({localTracks: {microphone: fakeMicrophoneTrack}});
1868
- await simulateRoapOffer();
1921
+ // and SDP offer was sent with the right audioMuted/videoMuted values
1922
+ checkSdpOfferSent({audioMuted: true, videoMuted: true});
1869
1923
 
1870
- // check RoapMediaConnection was created correctly
1871
- checkMediaConnectionCreated({
1872
- mediaConnectionConfig: expectedMediaConnectionConfig,
1873
- localTracks: {
1874
- audio: fakeMicrophoneTrack,
1875
- video: undefined,
1876
- screenShareVideo: undefined,
1877
- screenShareAudio: undefined,
1878
- },
1879
- direction: {
1880
- audio: 'sendrecv',
1881
- video: 'sendrecv',
1882
- screenShareVideo: 'recvonly',
1883
- },
1884
- remoteQualityLevel: 'HIGH',
1885
- expectedDebugId,
1886
- meetingId: meeting.id
1924
+ // and no other local mute requests were sent to Locus
1925
+ assert.calledOnce(locusMediaRequestStub);
1887
1926
  });
1888
1927
 
1889
- // and SDP offer was sent with the right audioMuted/videoMuted values
1890
- checkSdpOfferSent({audioMuted: true, videoMuted: true});
1928
+ it('addMedia() works correctly when media is disabled with tracks to publish', async () => {
1929
+ await meeting.addMedia({
1930
+ localTracks: {microphone: fakeMicrophoneTrack},
1931
+ audioEnabled: false,
1932
+ });
1933
+ await simulateRoapOffer();
1891
1934
 
1892
- // and no other local mute requests were sent to Locus
1893
- assert.calledOnce(locusMediaRequestStub);
1894
- });
1935
+ // check RoapMediaConnection was created correctly
1936
+ checkMediaConnectionCreated({
1937
+ mediaConnectionConfig: expectedMediaConnectionConfig,
1938
+ localTracks: {
1939
+ audio: fakeMicrophoneTrack,
1940
+ video: undefined,
1941
+ screenShareVideo: undefined,
1942
+ screenShareAudio: undefined,
1943
+ },
1944
+ direction: {
1945
+ audio: 'inactive',
1946
+ video: 'sendrecv',
1947
+ screenShareVideo: 'recvonly',
1948
+ },
1949
+ remoteQualityLevel: 'HIGH',
1950
+ expectedDebugId,
1951
+ meetingId: meeting.id,
1952
+ });
1895
1953
 
1896
- it('addMedia() works correctly when media is disabled with tracks to publish', async () => {
1897
- await meeting.addMedia({localTracks: {microphone: fakeMicrophoneTrack}, audioEnabled: false});
1898
- await simulateRoapOffer();
1954
+ // and SDP offer was sent with the right audioMuted/videoMuted values
1955
+ checkSdpOfferSent({audioMuted: true, videoMuted: true});
1899
1956
 
1900
- // check RoapMediaConnection was created correctly
1901
- checkMediaConnectionCreated({
1902
- mediaConnectionConfig: expectedMediaConnectionConfig,
1903
- localTracks: {
1904
- audio: fakeMicrophoneTrack,
1905
- video: undefined,
1906
- screenShareVideo: undefined,
1907
- screenShareAudio: undefined,
1908
- },
1909
- direction: {
1910
- audio: 'inactive',
1911
- video: 'sendrecv',
1912
- screenShareVideo: 'recvonly',
1913
- },
1914
- remoteQualityLevel: 'HIGH',
1915
- expectedDebugId,
1916
- meetingId: meeting.id
1957
+ // and no other local mute requests were sent to Locus
1958
+ assert.calledOnce(locusMediaRequestStub);
1917
1959
  });
1918
1960
 
1919
- // and SDP offer was sent with the right audioMuted/videoMuted values
1920
- checkSdpOfferSent({audioMuted: true, videoMuted: true});
1961
+ it('addMedia() works correctly when media is disabled with no tracks to publish', async () => {
1962
+ await meeting.addMedia({audioEnabled: false});
1963
+ await simulateRoapOffer();
1921
1964
 
1922
- // and no other local mute requests were sent to Locus
1923
- assert.calledOnce(locusMediaRequestStub);
1924
- });
1965
+ // check RoapMediaConnection was created correctly
1966
+ checkMediaConnectionCreated({
1967
+ mediaConnectionConfig: expectedMediaConnectionConfig,
1968
+ localTracks: {
1969
+ audio: undefined,
1970
+ video: undefined,
1971
+ screenShareVideo: undefined,
1972
+ screenShareAudio: undefined,
1973
+ },
1974
+ direction: {
1975
+ audio: 'inactive',
1976
+ video: 'sendrecv',
1977
+ screenShareVideo: 'recvonly',
1978
+ },
1979
+ remoteQualityLevel: 'HIGH',
1980
+ expectedDebugId,
1981
+ meetingId: meeting.id,
1982
+ });
1925
1983
 
1926
- it('addMedia() works correctly when media is disabled with no tracks to publish', async () => {
1927
- await meeting.addMedia({audioEnabled: false});
1928
- await simulateRoapOffer();
1984
+ // and SDP offer was sent with the right audioMuted/videoMuted values
1985
+ checkSdpOfferSent({audioMuted: true, videoMuted: true});
1929
1986
 
1930
- // check RoapMediaConnection was created correctly
1931
- checkMediaConnectionCreated({
1932
- mediaConnectionConfig: expectedMediaConnectionConfig,
1933
- localTracks: {
1934
- audio: undefined,
1935
- video: undefined,
1936
- screenShareVideo: undefined,
1937
- screenShareAudio: undefined,
1938
- },
1939
- direction: {
1940
- audio: 'inactive',
1941
- video: 'sendrecv',
1942
- screenShareVideo: 'recvonly',
1943
- },
1944
- remoteQualityLevel: 'HIGH',
1945
- expectedDebugId,
1946
- meetingId: meeting.id
1987
+ // and no other local mute requests were sent to Locus
1988
+ assert.calledOnce(locusMediaRequestStub);
1947
1989
  });
1948
1990
 
1949
- // and SDP offer was sent with the right audioMuted/videoMuted values
1950
- checkSdpOfferSent({audioMuted: true, videoMuted: true});
1951
-
1952
- // and no other local mute requests were sent to Locus
1953
- assert.calledOnce(locusMediaRequestStub);
1954
- });
1955
-
1956
- describe('publishTracks()/unpublishTracks() calls', () => {
1957
- [
1958
- {mediaEnabled: true, expected: {direction: 'sendrecv', localMuteSentValue: false}},
1959
- {mediaEnabled: false, expected: {direction: 'inactive', localMuteSentValue: undefined}}
1960
- ]
1961
- .forEach(({mediaEnabled, expected}) => {
1962
- it(`first publishTracks() call while media is ${mediaEnabled ? 'enabled' : 'disabled'}`, async () => {
1991
+ describe('publishTracks()/unpublishTracks() calls', () => {
1992
+ [
1993
+ {mediaEnabled: true, expected: {direction: 'sendrecv', localMuteSentValue: false}},
1994
+ {
1995
+ mediaEnabled: false,
1996
+ expected: {direction: 'inactive', localMuteSentValue: undefined},
1997
+ },
1998
+ ].forEach(({mediaEnabled, expected}) => {
1999
+ it(`first publishTracks() call while media is ${
2000
+ mediaEnabled ? 'enabled' : 'disabled'
2001
+ }`, async () => {
1963
2002
  await meeting.addMedia({audioEnabled: mediaEnabled});
1964
2003
  await simulateRoapOffer();
1965
2004
 
@@ -1970,27 +2009,35 @@ describe('plugin-meetings', () => {
1970
2009
 
1971
2010
  if (expected.localMuteSentValue !== undefined) {
1972
2011
  // check local mute was sent and it was the only /media request
1973
- checkLocalMuteSentToLocus({audioMuted: expected.localMuteSentValue, videoMuted: true});
2012
+ checkLocalMuteSentToLocus({
2013
+ audioMuted: expected.localMuteSentValue,
2014
+ videoMuted: true,
2015
+ });
1974
2016
  assert.calledOnce(locusMediaRequestStub);
1975
2017
  } else {
1976
2018
  assert.notCalled(locusMediaRequestStub);
1977
2019
  }
1978
2020
  if (isMultistream) {
1979
- assert.calledOnceWithExactly(fakeMultistreamRoapMediaConnection.publishTrack, fakeMicrophoneTrack);
2021
+ assert.calledOnceWithExactly(
2022
+ fakeMultistreamRoapMediaConnection.publishTrack,
2023
+ fakeMicrophoneTrack
2024
+ );
1980
2025
  } else {
1981
2026
  assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
1982
- localTracks: { audio: webrtcAudioTrack, video: null, screenShareVideo: null },
2027
+ localTracks: {audio: webrtcAudioTrack, video: null, screenShareVideo: null},
1983
2028
  direction: {
1984
2029
  audio: expected.direction,
1985
2030
  video: 'sendrecv',
1986
2031
  screenShareVideo: 'recvonly',
1987
2032
  },
1988
- remoteQualityLevel: 'HIGH'
2033
+ remoteQualityLevel: 'HIGH',
1989
2034
  });
1990
2035
  }
1991
2036
  });
1992
2037
 
1993
- it(`second publishTracks() call while media is ${mediaEnabled ? 'enabled' : 'disabled'}`, async () => {
2038
+ it(`second publishTracks() call while media is ${
2039
+ mediaEnabled ? 'enabled' : 'disabled'
2040
+ }`, async () => {
1994
2041
  await meeting.addMedia({audioEnabled: mediaEnabled});
1995
2042
  await simulateRoapOffer();
1996
2043
  await meeting.publishTracks({microphone: fakeMicrophoneTrack});
@@ -2007,7 +2054,7 @@ describe('plugin-meetings', () => {
2007
2054
  setMuted: sinon.stub(),
2008
2055
  setPublished: sinon.stub(),
2009
2056
  muted: false,
2010
- underlyingTrack: webrtcAudioTrack2
2057
+ underlyingTrack: webrtcAudioTrack2,
2011
2058
  };
2012
2059
 
2013
2060
  await meeting.publishTracks({microphone: fakeMicrophoneTrack2});
@@ -2015,16 +2062,19 @@ describe('plugin-meetings', () => {
2015
2062
 
2016
2063
  // only the roap media connection should be updated
2017
2064
  if (isMultistream) {
2018
- assert.calledOnceWithExactly(fakeMultistreamRoapMediaConnection.publishTrack, fakeMicrophoneTrack2);
2065
+ assert.calledOnceWithExactly(
2066
+ fakeMultistreamRoapMediaConnection.publishTrack,
2067
+ fakeMicrophoneTrack2
2068
+ );
2019
2069
  } else {
2020
2070
  assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
2021
- localTracks: { audio: webrtcAudioTrack2, video: null, screenShareVideo: null },
2071
+ localTracks: {audio: webrtcAudioTrack2, video: null, screenShareVideo: null},
2022
2072
  direction: {
2023
2073
  audio: expected.direction,
2024
2074
  video: 'sendrecv',
2025
2075
  screenShareVideo: 'recvonly',
2026
2076
  },
2027
- remoteQualityLevel: 'HIGH'
2077
+ remoteQualityLevel: 'HIGH',
2028
2078
  });
2029
2079
  }
2030
2080
 
@@ -2032,7 +2082,9 @@ describe('plugin-meetings', () => {
2032
2082
  assert.notCalled(locusMediaRequestStub);
2033
2083
  });
2034
2084
 
2035
- it(`unpublishTracks() call while media is ${mediaEnabled ? 'enabled' : 'disabled'}`, async () => {
2085
+ it(`unpublishTracks() call while media is ${
2086
+ mediaEnabled ? 'enabled' : 'disabled'
2087
+ }`, async () => {
2036
2088
  await meeting.addMedia({audioEnabled: mediaEnabled});
2037
2089
  await simulateRoapOffer();
2038
2090
  await meeting.publishTracks({microphone: fakeMicrophoneTrack});
@@ -2045,174 +2097,184 @@ describe('plugin-meetings', () => {
2045
2097
 
2046
2098
  // the roap media connection should be updated
2047
2099
  if (isMultistream) {
2048
- assert.calledOnceWithExactly(fakeMultistreamRoapMediaConnection.unpublishTrack, fakeMicrophoneTrack);
2100
+ assert.calledOnceWithExactly(
2101
+ fakeMultistreamRoapMediaConnection.unpublishTrack,
2102
+ fakeMicrophoneTrack
2103
+ );
2049
2104
  } else {
2050
2105
  assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
2051
- localTracks: { audio: null, video: null, screenShareVideo: null },
2106
+ localTracks: {audio: null, video: null, screenShareVideo: null},
2052
2107
  direction: {
2053
2108
  audio: expected.direction,
2054
2109
  video: 'sendrecv',
2055
2110
  screenShareVideo: 'recvonly',
2056
2111
  },
2057
- remoteQualityLevel: 'HIGH'
2112
+ remoteQualityLevel: 'HIGH',
2058
2113
  });
2059
2114
  }
2060
2115
 
2061
2116
  if (expected.localMuteSentValue !== undefined) {
2062
2117
  // and local mute sent to Locus
2063
- checkLocalMuteSentToLocus({audioMuted: !expected.localMuteSentValue /* negation, because we're un-publishing */, videoMuted: true});
2118
+ checkLocalMuteSentToLocus({
2119
+ audioMuted:
2120
+ !expected.localMuteSentValue /* negation, because we're un-publishing */,
2121
+ videoMuted: true,
2122
+ });
2064
2123
  assert.calledOnce(locusMediaRequestStub);
2065
2124
  } else {
2066
2125
  assert.notCalled(locusMediaRequestStub);
2067
2126
  }
2068
2127
  });
2069
2128
  });
2070
- });
2129
+ });
2071
2130
 
2072
- describe('updateMedia()', () => {
2131
+ describe('updateMedia()', () => {
2132
+ const addMedia = async (enableMedia, track) => {
2133
+ await meeting.addMedia({audioEnabled: enableMedia, localTracks: {microphone: track}});
2134
+ await simulateRoapOffer();
2073
2135
 
2074
- const addMedia = async (enableMedia, track) => {
2075
- await meeting.addMedia({audioEnabled: enableMedia, localTracks: {microphone: track}});
2076
- await simulateRoapOffer();
2077
-
2078
- resetHistory();
2079
- }
2136
+ resetHistory();
2137
+ };
2080
2138
 
2081
- const checkAudioEnabled = (expectedTrack, expectedDirection) => {
2082
- if (isMultistream) {
2083
- assert.calledOnceWithExactly(fakeMultistreamRoapMediaConnection.enableMultistreamAudio, expectedDirection !== 'inactive');
2084
- } else {
2085
- assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
2086
- localTracks: { audio: expectedTrack, video: null, screenShareVideo: null },
2087
- direction: {
2088
- audio: expectedDirection,
2089
- video: 'sendrecv',
2090
- screenShareVideo: 'recvonly',
2091
- },
2092
- remoteQualityLevel: 'HIGH'
2093
- });
2094
- }
2095
- }
2139
+ const checkAudioEnabled = (expectedTrack, expectedDirection) => {
2140
+ if (isMultistream) {
2141
+ assert.calledOnceWithExactly(
2142
+ fakeMultistreamRoapMediaConnection.enableMultistreamAudio,
2143
+ expectedDirection !== 'inactive'
2144
+ );
2145
+ } else {
2146
+ assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
2147
+ localTracks: {audio: expectedTrack, video: null, screenShareVideo: null},
2148
+ direction: {
2149
+ audio: expectedDirection,
2150
+ video: 'sendrecv',
2151
+ screenShareVideo: 'recvonly',
2152
+ },
2153
+ remoteQualityLevel: 'HIGH',
2154
+ });
2155
+ }
2156
+ };
2096
2157
 
2097
- it('updateMedia() disables media when nothing is published', async () => {
2098
- await addMedia(true);
2158
+ it('updateMedia() disables media when nothing is published', async () => {
2159
+ await addMedia(true);
2099
2160
 
2100
- await meeting.updateMedia({audioEnabled: false});
2161
+ await meeting.updateMedia({audioEnabled: false});
2101
2162
 
2102
- // the roap media connection should be updated
2103
- checkAudioEnabled(null, 'inactive');
2163
+ // the roap media connection should be updated
2164
+ checkAudioEnabled(null, 'inactive');
2104
2165
 
2105
- // and that would trigger a new offer so we simulate it happening
2106
- await simulateRoapOffer();
2166
+ // and that would trigger a new offer so we simulate it happening
2167
+ await simulateRoapOffer();
2107
2168
 
2108
- // check SDP offer was sent with the right audioMuted/videoMuted values
2109
- checkSdpOfferSent({audioMuted: true, videoMuted: true});
2169
+ // check SDP offer was sent with the right audioMuted/videoMuted values
2170
+ checkSdpOfferSent({audioMuted: true, videoMuted: true});
2110
2171
 
2111
- // and no other local mute requests were sent to Locus
2112
- assert.calledOnce(locusMediaRequestStub);
2113
- });
2172
+ // and no other local mute requests were sent to Locus
2173
+ assert.calledOnce(locusMediaRequestStub);
2174
+ });
2114
2175
 
2115
- it('updateMedia() enables media when nothing is published', async () => {
2116
- await addMedia(false);
2176
+ it('updateMedia() enables media when nothing is published', async () => {
2177
+ await addMedia(false);
2117
2178
 
2118
- await meeting.updateMedia({audioEnabled: true});
2179
+ await meeting.updateMedia({audioEnabled: true});
2119
2180
 
2120
- // the roap media connection should be updated
2121
- checkAudioEnabled(null, 'sendrecv');
2181
+ // the roap media connection should be updated
2182
+ checkAudioEnabled(null, 'sendrecv');
2122
2183
 
2123
- // and that would trigger a new offer so we simulate it happening
2124
- await simulateRoapOffer();
2184
+ // and that would trigger a new offer so we simulate it happening
2185
+ await simulateRoapOffer();
2125
2186
 
2126
- // check SDP offer was sent with the right audioMuted/videoMuted values
2127
- checkSdpOfferSent({audioMuted: true, videoMuted: true});
2187
+ // check SDP offer was sent with the right audioMuted/videoMuted values
2188
+ checkSdpOfferSent({audioMuted: true, videoMuted: true});
2128
2189
 
2129
- // and no other local mute requests were sent to Locus
2130
- assert.calledOnce(locusMediaRequestStub);
2131
- });
2190
+ // and no other local mute requests were sent to Locus
2191
+ assert.calledOnce(locusMediaRequestStub);
2192
+ });
2132
2193
 
2133
- it('updateMedia() disables media when track is published', async () => {
2134
- await addMedia(true, fakeMicrophoneTrack);
2194
+ it('updateMedia() disables media when track is published', async () => {
2195
+ await addMedia(true, fakeMicrophoneTrack);
2135
2196
 
2136
- await meeting.updateMedia({audioEnabled: false});
2137
- await stableState();
2197
+ await meeting.updateMedia({audioEnabled: false});
2198
+ await stableState();
2138
2199
 
2139
- // the roap media connection should be updated
2140
- checkAudioEnabled(webrtcAudioTrack, 'inactive');
2200
+ // the roap media connection should be updated
2201
+ checkAudioEnabled(webrtcAudioTrack, 'inactive');
2141
2202
 
2142
- checkLocalMuteSentToLocus({audioMuted: true, videoMuted: true});
2203
+ checkLocalMuteSentToLocus({audioMuted: true, videoMuted: true});
2143
2204
 
2144
- locusMediaRequestStub.resetHistory();
2205
+ locusMediaRequestStub.resetHistory();
2145
2206
 
2146
- // and that would trigger a new offer so we simulate it happening
2147
- await simulateRoapOffer();
2207
+ // and that would trigger a new offer so we simulate it happening
2208
+ await simulateRoapOffer();
2148
2209
 
2149
- // check SDP offer was sent with the right audioMuted/videoMuted values
2150
- checkSdpOfferSent({audioMuted: true, videoMuted: true});
2210
+ // check SDP offer was sent with the right audioMuted/videoMuted values
2211
+ checkSdpOfferSent({audioMuted: true, videoMuted: true});
2151
2212
 
2152
- // and no other local mute requests were sent to Locus
2153
- assert.calledOnce(locusMediaRequestStub);
2154
- });
2213
+ // and no other local mute requests were sent to Locus
2214
+ assert.calledOnce(locusMediaRequestStub);
2215
+ });
2155
2216
 
2156
- it('updateMedia() enables media when track is published', async () => {
2157
- await addMedia(false, fakeMicrophoneTrack);
2217
+ it('updateMedia() enables media when track is published', async () => {
2218
+ await addMedia(false, fakeMicrophoneTrack);
2158
2219
 
2159
- await meeting.updateMedia({audioEnabled: true});
2160
- await stableState();
2220
+ await meeting.updateMedia({audioEnabled: true});
2221
+ await stableState();
2161
2222
 
2162
- // the roap media connection should be updated
2163
- checkAudioEnabled(webrtcAudioTrack, 'sendrecv');
2223
+ // the roap media connection should be updated
2224
+ checkAudioEnabled(webrtcAudioTrack, 'sendrecv');
2164
2225
 
2165
- checkLocalMuteSentToLocus({audioMuted: false, videoMuted: true});
2226
+ checkLocalMuteSentToLocus({audioMuted: false, videoMuted: true});
2166
2227
 
2167
- locusMediaRequestStub.resetHistory();
2228
+ locusMediaRequestStub.resetHistory();
2168
2229
 
2169
- // and that would trigger a new offer so we simulate it happening
2170
- await simulateRoapOffer();
2230
+ // and that would trigger a new offer so we simulate it happening
2231
+ await simulateRoapOffer();
2171
2232
 
2172
- // check SDP offer was sent with the right audioMuted/videoMuted values
2173
- checkSdpOfferSent({audioMuted: false, videoMuted: true});
2233
+ // check SDP offer was sent with the right audioMuted/videoMuted values
2234
+ checkSdpOfferSent({audioMuted: false, videoMuted: true});
2174
2235
 
2175
- // and no other local mute requests were sent to Locus
2176
- assert.calledOnce(locusMediaRequestStub);
2236
+ // and no other local mute requests were sent to Locus
2237
+ assert.calledOnce(locusMediaRequestStub);
2238
+ });
2177
2239
  });
2178
- });
2179
2240
 
2180
- [
2181
- {mute: true, title: 'muting a track before confluence is created'},
2182
- {mute: false, title: 'unmuting a track before confluence is created'}
2183
- ].forEach(({mute, title}) =>
2184
- it(title, async () => {
2185
- // initialize the microphone mute state to opposite of what we do in the test
2186
- fakeMicrophoneTrack.muted = !mute;
2241
+ [
2242
+ {mute: true, title: 'muting a track before confluence is created'},
2243
+ {mute: false, title: 'unmuting a track before confluence is created'},
2244
+ ].forEach(({mute, title}) =>
2245
+ it(title, async () => {
2246
+ // initialize the microphone mute state to opposite of what we do in the test
2247
+ fakeMicrophoneTrack.muted = !mute;
2187
2248
 
2188
- await meeting.addMedia({localTracks: {microphone: fakeMicrophoneTrack}});
2189
- await stableState();
2249
+ await meeting.addMedia({localTracks: {microphone: fakeMicrophoneTrack}});
2250
+ await stableState();
2190
2251
 
2191
- resetHistory();
2252
+ resetHistory();
2192
2253
 
2193
- assert.equal(fakeMicrophoneTrack.on.getCall(0).args[0], LocalTrackEvents.Muted);
2194
- const mutedListener = fakeMicrophoneTrack.on.getCall(0).args[1];
2195
- // simulate track being muted
2196
- mutedListener({trackState: {muted: mute}});
2254
+ assert.equal(fakeMicrophoneTrack.on.getCall(0).args[0], LocalTrackEvents.Muted);
2255
+ const mutedListener = fakeMicrophoneTrack.on.getCall(0).args[1];
2256
+ // simulate track being muted
2257
+ mutedListener({trackState: {muted: mute}});
2197
2258
 
2198
- await stableState();
2259
+ await stableState();
2199
2260
 
2200
- // nothing should happen
2201
- assert.notCalled(locusMediaRequestStub);
2202
- assert.notCalled(fakeRoapMediaConnection.update);
2261
+ // nothing should happen
2262
+ assert.notCalled(locusMediaRequestStub);
2263
+ assert.notCalled(fakeRoapMediaConnection.update);
2203
2264
 
2204
- // now simulate roap offer
2205
- await simulateRoapOffer();
2265
+ // now simulate roap offer
2266
+ await simulateRoapOffer();
2206
2267
 
2207
- // it should be sent with the right mute status
2208
- checkSdpOfferSent({audioMuted: mute, videoMuted: true});
2268
+ // it should be sent with the right mute status
2269
+ checkSdpOfferSent({audioMuted: mute, videoMuted: true});
2209
2270
 
2210
- // nothing else should happen
2211
- assert.calledOnce(locusMediaRequestStub);
2212
- assert.notCalled(fakeRoapMediaConnection.update);
2213
- })
2214
- );
2215
- }));
2271
+ // nothing else should happen
2272
+ assert.calledOnce(locusMediaRequestStub);
2273
+ assert.notCalled(fakeRoapMediaConnection.update);
2274
+ })
2275
+ );
2276
+ })
2277
+ );
2216
2278
 
2217
2279
  describe('#acknowledge', () => {
2218
2280
  it('should have #acknowledge', () => {
@@ -2313,7 +2375,9 @@ describe('plugin-meetings', () => {
2313
2375
 
2314
2376
  assert.exists(leave.then);
2315
2377
  await leave;
2316
- assert.calledWith(webex.internal.newMetrics.submitInternalEvent, {name: 'internal.reset.join.latencies'});
2378
+ assert.calledWith(webex.internal.newMetrics.submitInternalEvent, {
2379
+ name: 'internal.reset.join.latencies',
2380
+ });
2317
2381
  });
2318
2382
 
2319
2383
  describe('after audio/video is defined', () => {
@@ -2359,11 +2423,14 @@ describe('plugin-meetings', () => {
2359
2423
  correlationId: meeting.correlationId,
2360
2424
  selfId: meeting.selfId,
2361
2425
  resourceId: meeting.resourceId,
2362
- deviceUrl: meeting.deviceUrl
2426
+ deviceUrl: meeting.deviceUrl,
2363
2427
  });
2364
2428
  });
2365
2429
  it('should leave the meeting on the resource with reason', async () => {
2366
- const leave = meeting.leave({resourceId: meeting.resourceId, reason: MEETING_REMOVED_REASON.CLIENT_LEAVE_REQUEST});
2430
+ const leave = meeting.leave({
2431
+ resourceId: meeting.resourceId,
2432
+ reason: MEETING_REMOVED_REASON.CLIENT_LEAVE_REQUEST,
2433
+ });
2367
2434
 
2368
2435
  assert.exists(leave.then);
2369
2436
  await leave;
@@ -2373,7 +2440,7 @@ describe('plugin-meetings', () => {
2373
2440
  selfId: meeting.selfId,
2374
2441
  resourceId: meeting.resourceId,
2375
2442
  deviceUrl: meeting.deviceUrl,
2376
- reason: MEETING_REMOVED_REASON.CLIENT_LEAVE_REQUEST
2443
+ reason: MEETING_REMOVED_REASON.CLIENT_LEAVE_REQUEST,
2377
2444
  });
2378
2445
  });
2379
2446
  });
@@ -2444,12 +2511,12 @@ describe('plugin-meetings', () => {
2444
2511
  let sandbox;
2445
2512
 
2446
2513
  const createFakeLocalTrack = () => ({
2447
- underlyingTrack: {id: 'fake underlying track'}
2514
+ underlyingTrack: {id: 'fake underlying track'},
2448
2515
  });
2449
2516
  beforeEach(() => {
2450
2517
  sandbox = sinon.createSandbox();
2451
- meeting.audio = { enable: sinon.stub()};
2452
- meeting.video = { enable: sinon.stub()};
2518
+ meeting.audio = {enable: sinon.stub()};
2519
+ meeting.video = {enable: sinon.stub()};
2453
2520
  meeting.mediaProperties.audioTrack = createFakeLocalTrack();
2454
2521
  meeting.mediaProperties.videoTrack = createFakeLocalTrack();
2455
2522
  meeting.mediaProperties.shareVideoTrack = createFakeLocalTrack();
@@ -2460,7 +2527,7 @@ describe('plugin-meetings', () => {
2460
2527
  receiveAudio: true,
2461
2528
  receiveVideo: true,
2462
2529
  receiveShare: true,
2463
- }
2530
+ };
2464
2531
  });
2465
2532
 
2466
2533
  afterEach(() => {
@@ -2499,11 +2566,9 @@ describe('plugin-meetings', () => {
2499
2566
 
2500
2567
  let myPromiseResolved = false;
2501
2568
 
2502
- meeting
2503
- .updateMedia({audioEnabled: false, videoEnabled: false})
2504
- .then(() => {
2505
- myPromiseResolved = true;
2506
- });
2569
+ meeting.updateMedia({audioEnabled: false, videoEnabled: false}).then(() => {
2570
+ myPromiseResolved = true;
2571
+ });
2507
2572
 
2508
2573
  // verify that nothing was done
2509
2574
  assert.notCalled(meeting.mediaProperties.webrtcMediaConnection.update);
@@ -2517,22 +2582,19 @@ describe('plugin-meetings', () => {
2517
2582
 
2518
2583
  // and check that update is called with the original args
2519
2584
  assert.calledOnce(meeting.mediaProperties.webrtcMediaConnection.update);
2520
- assert.calledWith(
2521
- meeting.mediaProperties.webrtcMediaConnection.update,
2522
- {
2523
- localTracks: {
2524
- audio: meeting.mediaProperties.audioTrack.underlyingTrack,
2525
- video: meeting.mediaProperties.videoTrack.underlyingTrack,
2526
- screenShareVideo: meeting.mediaProperties.shareVideoTrack.underlyingTrack,
2527
- },
2528
- direction: {
2529
- audio: 'inactive',
2530
- video: 'inactive',
2531
- screenShareVideo: 'sendrecv',
2532
- },
2533
- remoteQualityLevel: 'HIGH',
2534
- }
2535
- );
2585
+ assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.update, {
2586
+ localTracks: {
2587
+ audio: meeting.mediaProperties.audioTrack.underlyingTrack,
2588
+ video: meeting.mediaProperties.videoTrack.underlyingTrack,
2589
+ screenShareVideo: meeting.mediaProperties.shareVideoTrack.underlyingTrack,
2590
+ },
2591
+ direction: {
2592
+ audio: 'inactive',
2593
+ video: 'inactive',
2594
+ screenShareVideo: 'sendrecv',
2595
+ },
2596
+ remoteQualityLevel: 'HIGH',
2597
+ });
2536
2598
  assert.isTrue(myPromiseResolved);
2537
2599
  });
2538
2600
  });
@@ -2915,15 +2977,15 @@ describe('plugin-meetings', () => {
2915
2977
  });
2916
2978
  });
2917
2979
 
2918
- describe("#isJoined", () => {
2919
- it("should returns isJoined correctly", () => {
2980
+ describe('#isJoined', () => {
2981
+ it('should returns isJoined correctly', () => {
2920
2982
  meeting.joinedWith = undefined;
2921
2983
  assert.equal(meeting.isJoined(), false);
2922
2984
 
2923
- meeting.joinedWith = {state: "NOT_JOINED"};
2985
+ meeting.joinedWith = {state: 'NOT_JOINED'};
2924
2986
  assert.equal(meeting.isJoined(), false);
2925
2987
 
2926
- meeting.joinedWith = {state: "JOINED"};
2988
+ meeting.joinedWith = {state: 'JOINED'};
2927
2989
  assert.equal(meeting.isJoined(), true);
2928
2990
  });
2929
2991
  });
@@ -2939,7 +3001,10 @@ describe('plugin-meetings', () => {
2939
3001
  const FAKE_CAPTCHA_AUDIO_URL = 'http://captchaaudio';
2940
3002
  const FAKE_CAPTCHA_REFRESH_URL = 'http://captcharefresh';
2941
3003
  const FAKE_INSTALLED_ORG_ID = '123456';
2942
- const FAKE_EXTRA_PARAMS = {mtid: 'm9fe0afd8c435e892afcce9ea25b97046', joinTXId: 'TSmrX61wNF'};
3004
+ const FAKE_EXTRA_PARAMS = {
3005
+ mtid: 'm9fe0afd8c435e892afcce9ea25b97046',
3006
+ joinTXId: 'TSmrX61wNF',
3007
+ };
2943
3008
  let FAKE_OPTIONS;
2944
3009
  const FAKE_MEETING_INFO = {
2945
3010
  conversationUrl: 'some_convo_url',
@@ -2971,7 +3036,9 @@ describe('plugin-meetings', () => {
2971
3036
 
2972
3037
  it('calls meetingInfoProvider with all the right parameters and parses the result', async () => {
2973
3038
  meeting.attrs.meetingInfoProvider = {
2974
- fetchMeetingInfo: sinon.stub().resolves({body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL}),
3039
+ fetchMeetingInfo: sinon
3040
+ .stub()
3041
+ .resolves({body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL}),
2975
3042
  };
2976
3043
  meeting.requiredCaptcha = FAKE_SDK_CAPTCHA_INFO;
2977
3044
  meeting.destination = FAKE_DESTINATION;
@@ -2997,8 +3064,15 @@ describe('plugin-meetings', () => {
2997
3064
  FAKE_OPTIONS
2998
3065
  );
2999
3066
 
3000
- assert.calledWith(meeting.parseMeetingInfo, {body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL}, FAKE_DESTINATION);
3001
- assert.deepEqual(meeting.meetingInfo, {...FAKE_MEETING_INFO, meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL});
3067
+ assert.calledWith(
3068
+ meeting.parseMeetingInfo,
3069
+ {body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL},
3070
+ FAKE_DESTINATION
3071
+ );
3072
+ assert.deepEqual(meeting.meetingInfo, {
3073
+ ...FAKE_MEETING_INFO,
3074
+ meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
3075
+ });
3002
3076
  assert.equal(meeting.passwordStatus, PASSWORD_STATUS.NOT_REQUIRED);
3003
3077
  assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
3004
3078
  assert.equal(meeting.requiredCaptcha, null);
@@ -3013,7 +3087,9 @@ describe('plugin-meetings', () => {
3013
3087
 
3014
3088
  it('calls meetingInfoProvider with all the right parameters and parses the result when random delay is applied', async () => {
3015
3089
  meeting.attrs.meetingInfoProvider = {
3016
- fetchMeetingInfo: sinon.stub().resolves({body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL}),
3090
+ fetchMeetingInfo: sinon
3091
+ .stub()
3092
+ .resolves({body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL}),
3017
3093
  };
3018
3094
  meeting.destination = FAKE_DESTINATION;
3019
3095
  meeting.destinationType = FAKE_TYPE;
@@ -3044,9 +3120,16 @@ describe('plugin-meetings', () => {
3044
3120
  );
3045
3121
 
3046
3122
  // parseMeeting info
3047
- assert.calledWith(meeting.parseMeetingInfo, {body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL}, FAKE_DESTINATION);
3123
+ assert.calledWith(
3124
+ meeting.parseMeetingInfo,
3125
+ {body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL},
3126
+ FAKE_DESTINATION
3127
+ );
3048
3128
 
3049
- assert.deepEqual(meeting.meetingInfo, {...FAKE_MEETING_INFO, meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL});
3129
+ assert.deepEqual(meeting.meetingInfo, {
3130
+ ...FAKE_MEETING_INFO,
3131
+ meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
3132
+ });
3050
3133
  assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
3051
3134
  assert.equal(meeting.requiredCaptcha, null);
3052
3135
  assert.equal(meeting.passwordStatus, PASSWORD_STATUS.NOT_REQUIRED);
@@ -3062,7 +3145,9 @@ describe('plugin-meetings', () => {
3062
3145
 
3063
3146
  it('fails if captchaCode is provided when captcha not needed', async () => {
3064
3147
  meeting.attrs.meetingInfoProvider = {
3065
- fetchMeetingInfo: sinon.stub().resolves({body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL}),
3148
+ fetchMeetingInfo: sinon
3149
+ .stub()
3150
+ .resolves({body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL}),
3066
3151
  };
3067
3152
  meeting.requiredCaptcha = null;
3068
3153
  meeting.destination = FAKE_DESTINATION;
@@ -3081,7 +3166,9 @@ describe('plugin-meetings', () => {
3081
3166
 
3082
3167
  it('fails if password is provided when not required', async () => {
3083
3168
  meeting.attrs.meetingInfoProvider = {
3084
- fetchMeetingInfo: sinon.stub().resolves({body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL}),
3169
+ fetchMeetingInfo: sinon
3170
+ .stub()
3171
+ .resolves({body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL}),
3085
3172
  };
3086
3173
  meeting.passwordStatus = PASSWORD_STATUS.NOT_REQUIRED;
3087
3174
  meeting.destination = FAKE_DESTINATION;
@@ -3118,7 +3205,7 @@ describe('plugin-meetings', () => {
3118
3205
  undefined,
3119
3206
  'locus-id',
3120
3207
  {},
3121
- {meetingId: meeting.id},
3208
+ {meetingId: meeting.id}
3122
3209
  );
3123
3210
 
3124
3211
  assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
@@ -3151,18 +3238,14 @@ describe('plugin-meetings', () => {
3151
3238
  undefined,
3152
3239
  'locus-id',
3153
3240
  {},
3154
- {meetingId: meeting.id},
3241
+ {meetingId: meeting.id}
3155
3242
  );
3156
3243
 
3157
3244
  assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
3158
3245
  assert.equal(meeting.meetingInfoFailureCode, 123456);
3159
- assert.equal(
3160
- meeting.meetingInfoFailureReason,
3161
- MEETING_INFO_FAILURE_REASON.POLICY
3162
- );
3246
+ assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.POLICY);
3163
3247
  });
3164
3248
 
3165
-
3166
3249
  it('handles meetingInfoProvider requiring captcha because of wrong password', async () => {
3167
3250
  meeting.destination = FAKE_DESTINATION;
3168
3251
  meeting.destinationType = FAKE_TYPE;
@@ -3189,7 +3272,7 @@ describe('plugin-meetings', () => {
3189
3272
  undefined,
3190
3273
  'locus-id',
3191
3274
  {},
3192
- {meetingId: meeting.id},
3275
+ {meetingId: meeting.id}
3193
3276
  );
3194
3277
 
3195
3278
  assert.deepEqual(meeting.meetingInfo, {});
@@ -3197,7 +3280,7 @@ describe('plugin-meetings', () => {
3197
3280
  meeting.meetingInfoFailureReason,
3198
3281
  MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD
3199
3282
  );
3200
- assert.equal(meeting.meetingInfoFailureCode, 423005);
3283
+ assert.equal(meeting.meetingInfoFailureCode, 423005);
3201
3284
  assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
3202
3285
  assert.deepEqual(meeting.requiredCaptcha, {
3203
3286
  captchaId: FAKE_CAPTCHA_ID,
@@ -3267,10 +3350,13 @@ describe('plugin-meetings', () => {
3267
3350
  undefined,
3268
3351
  'locus-id',
3269
3352
  {},
3270
- {meetingId: meeting.id},
3353
+ {meetingId: meeting.id}
3271
3354
  );
3272
3355
 
3273
- assert.deepEqual(meeting.meetingInfo, {...FAKE_MEETING_INFO, meetingLookupUrl: undefined});
3356
+ assert.deepEqual(meeting.meetingInfo, {
3357
+ ...FAKE_MEETING_INFO,
3358
+ meetingLookupUrl: undefined,
3359
+ });
3274
3360
  assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
3275
3361
  assert.equal(meeting.passwordStatus, PASSWORD_STATUS.VERIFIED);
3276
3362
  assert.equal(meeting.requiredCaptcha, null);
@@ -3316,7 +3402,7 @@ describe('plugin-meetings', () => {
3316
3402
  undefined,
3317
3403
  'locus-id',
3318
3404
  {},
3319
- {meetingId: meeting.id},
3405
+ {meetingId: meeting.id}
3320
3406
  );
3321
3407
 
3322
3408
  assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
@@ -3468,12 +3554,11 @@ describe('plugin-meetings', () => {
3468
3554
 
3469
3555
  it('should trigger `submitClientEvent`', async () => {
3470
3556
  await meeting.postMetrics('client.call.leave');
3471
- console.log({s: webex.internal.newMetrics.submitClientEvent.getCall(0).args[0]})
3557
+ console.log({s: webex.internal.newMetrics.submitClientEvent.getCall(0).args[0]});
3472
3558
  assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
3473
3559
  name: 'client.call.leave',
3474
3560
  options: {meetingId: meeting.id},
3475
3561
  });
3476
-
3477
3562
  });
3478
3563
  });
3479
3564
 
@@ -3586,7 +3671,7 @@ describe('plugin-meetings', () => {
3586
3671
  });
3587
3672
  assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
3588
3673
  name: 'client.call.move-media',
3589
- options: {meetingId: meeting.id}
3674
+ options: {meetingId: meeting.id},
3590
3675
  });
3591
3676
  });
3592
3677
 
@@ -3767,7 +3852,7 @@ describe('plugin-meetings', () => {
3767
3852
  on: sinon.stub(),
3768
3853
  off: sinon.stub(),
3769
3854
  getSettings: sinon.stub(),
3770
- }
3855
+ };
3771
3856
  videoShareTrack = {
3772
3857
  id: 'share track',
3773
3858
  on: sinon.stub(),
@@ -3786,8 +3871,8 @@ describe('plugin-meetings', () => {
3786
3871
  publishTrack: sinon.stub().resolves({}),
3787
3872
  unpublishTrack: sinon.stub().resolves({}),
3788
3873
  };
3789
- meeting.audio = { handleLocalTrackChange: sinon.stub()};
3790
- meeting.video = { handleLocalTrackChange: sinon.stub()};
3874
+ meeting.audio = {handleLocalTrackChange: sinon.stub()};
3875
+ meeting.video = {handleLocalTrackChange: sinon.stub()};
3791
3876
 
3792
3877
  const createFakeLocalTrack = (originalTrack) => ({
3793
3878
  on: sinon.stub(),
@@ -3829,10 +3914,7 @@ describe('plugin-meetings', () => {
3829
3914
 
3830
3915
  const checkAudioPublished = (track) => {
3831
3916
  assert.calledOnceWithExactly(meeting.audio.handleLocalTrackChange, meeting);
3832
- assert.calledWith(
3833
- meeting.mediaProperties.webrtcMediaConnection.publishTrack,
3834
- track
3835
- );
3917
+ assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.publishTrack, track);
3836
3918
  assert.equal(meeting.mediaProperties.audioTrack, track);
3837
3919
  // check that sendAudio hasn't been touched
3838
3920
  assert.equal(meeting.mediaProperties.mediaDirection.sendAudio, 'fake value');
@@ -3840,10 +3922,7 @@ describe('plugin-meetings', () => {
3840
3922
 
3841
3923
  const checkVideoPublished = (track) => {
3842
3924
  assert.calledOnceWithExactly(meeting.video.handleLocalTrackChange, meeting);
3843
- assert.calledWith(
3844
- meeting.mediaProperties.webrtcMediaConnection.publishTrack,
3845
- track
3846
- );
3925
+ assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.publishTrack, track);
3847
3926
  assert.equal(meeting.mediaProperties.videoTrack, track);
3848
3927
  // check that sendVideo hasn't been touched
3849
3928
  assert.equal(meeting.mediaProperties.mediaDirection.sendVideo, 'fake value');
@@ -3852,10 +3931,7 @@ describe('plugin-meetings', () => {
3852
3931
  const checkScreenShareVideoPublished = (track) => {
3853
3932
  assert.calledOnce(meeting.requestScreenShareFloor);
3854
3933
 
3855
- assert.calledWith(
3856
- meeting.mediaProperties.webrtcMediaConnection.publishTrack,
3857
- track
3858
- );
3934
+ assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.publishTrack, track);
3859
3935
  assert.equal(meeting.mediaProperties.shareVideoTrack, track);
3860
3936
  assert.equal(meeting.mediaProperties.mediaDirection.sendShare, true);
3861
3937
  };
@@ -3863,10 +3939,7 @@ describe('plugin-meetings', () => {
3863
3939
  const checkScreenShareAudioPublished = (track) => {
3864
3940
  assert.calledOnce(meeting.requestScreenShareFloor);
3865
3941
 
3866
- assert.calledWith(
3867
- meeting.mediaProperties.webrtcMediaConnection.publishTrack,
3868
- track
3869
- );
3942
+ assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.publishTrack, track);
3870
3943
  assert.equal(meeting.mediaProperties.shareAudioTrack, track);
3871
3944
  assert.equal(meeting.mediaProperties.mediaDirection.sendShare, true);
3872
3945
  };
@@ -3892,7 +3965,7 @@ describe('plugin-meetings', () => {
3892
3965
  meeting.requestScreenShareFloor.reset();
3893
3966
  await meeting.publishTracks({screenShare: {video: videoShareTrack}});
3894
3967
  assert.notCalled(meeting.requestScreenShareFloor);
3895
- })
3968
+ });
3896
3969
 
3897
3970
  it('does not request screen share floor when publishing audio share track if already sharing video', async () => {
3898
3971
  await meeting.publishTracks({screenShare: {video: videoShareTrack}});
@@ -3901,7 +3974,7 @@ describe('plugin-meetings', () => {
3901
3974
  meeting.requestScreenShareFloor.reset();
3902
3975
  await meeting.publishTracks({screenShare: {audio: audioShareTrack}});
3903
3976
  assert.notCalled(meeting.requestScreenShareFloor);
3904
- })
3977
+ });
3905
3978
 
3906
3979
  it('updates MuteState instance and publishes the track for main audio', async () => {
3907
3980
  await meeting.publishTracks({microphone: audioTrack});
@@ -4006,7 +4079,12 @@ describe('plugin-meetings', () => {
4006
4079
  });
4007
4080
 
4008
4081
  it('un-publishes the tracks correctly (all 4 together)', async () => {
4009
- await meeting.unpublishTracks([audioTrack, videoTrack, videoShareTrack, audioShareTrack]);
4082
+ await meeting.unpublishTracks([
4083
+ audioTrack,
4084
+ videoTrack,
4085
+ videoShareTrack,
4086
+ audioShareTrack,
4087
+ ]);
4010
4088
 
4011
4089
  assert.equal(meeting.mediaProperties.webrtcMediaConnection.unpublishTrack.callCount, 4);
4012
4090
  checkAudioUnpublished();
@@ -4066,36 +4144,40 @@ describe('plugin-meetings', () => {
4066
4144
  describe('#enableMusicMode', () => {
4067
4145
  beforeEach(() => {
4068
4146
  meeting.isMultistream = true;
4069
- meeting.mediaProperties.webrtcMediaConnection = {
4070
- setCodecParameters: sinon.stub().resolves({}),
4071
- deleteCodecParameters: sinon.stub().resolves({}),
4072
- };
4073
- });
4074
- [
4075
- {shouldEnableMusicMode: true},
4076
- {shouldEnableMusicMode: false},
4077
- ].forEach(({shouldEnableMusicMode}) => {
4078
- it(`fails if there is no media connection for shouldEnableMusicMode: ${shouldEnableMusicMode}`, async () => {
4079
- meeting.mediaProperties.webrtcMediaConnection = undefined;
4080
- await assert.isRejected(meeting.enableMusicMode(shouldEnableMusicMode));
4081
- });
4147
+ meeting.mediaProperties.webrtcMediaConnection = {
4148
+ setCodecParameters: sinon.stub().resolves({}),
4149
+ deleteCodecParameters: sinon.stub().resolves({}),
4150
+ };
4082
4151
  });
4152
+ [{shouldEnableMusicMode: true}, {shouldEnableMusicMode: false}].forEach(
4153
+ ({shouldEnableMusicMode}) => {
4154
+ it(`fails if there is no media connection for shouldEnableMusicMode: ${shouldEnableMusicMode}`, async () => {
4155
+ meeting.mediaProperties.webrtcMediaConnection = undefined;
4156
+ await assert.isRejected(meeting.enableMusicMode(shouldEnableMusicMode));
4157
+ });
4158
+ }
4159
+ );
4083
4160
 
4084
4161
  it('should set the codec parameters when shouldEnableMusicMode is true', async () => {
4085
4162
  await meeting.enableMusicMode(true);
4086
- assert.calledOnceWithExactly(meeting.mediaProperties.webrtcMediaConnection.setCodecParameters, MediaType.AudioMain, {
4087
- maxaveragebitrate: '64000',
4088
- maxplaybackrate: '48000',
4089
- });
4163
+ assert.calledOnceWithExactly(
4164
+ meeting.mediaProperties.webrtcMediaConnection.setCodecParameters,
4165
+ MediaType.AudioMain,
4166
+ {
4167
+ maxaveragebitrate: '64000',
4168
+ maxplaybackrate: '48000',
4169
+ }
4170
+ );
4090
4171
  assert.notCalled(meeting.mediaProperties.webrtcMediaConnection.deleteCodecParameters);
4091
4172
  });
4092
4173
 
4093
4174
  it('should set the codec parameters when shouldEnableMusicMode is false', async () => {
4094
4175
  await meeting.enableMusicMode(false);
4095
- assert.calledOnceWithExactly(meeting.mediaProperties.webrtcMediaConnection.deleteCodecParameters, MediaType.AudioMain, [
4096
- 'maxaveragebitrate',
4097
- 'maxplaybackrate',
4098
- ]);
4176
+ assert.calledOnceWithExactly(
4177
+ meeting.mediaProperties.webrtcMediaConnection.deleteCodecParameters,
4178
+ MediaType.AudioMain,
4179
+ ['maxaveragebitrate', 'maxplaybackrate']
4180
+ );
4099
4181
  assert.notCalled(meeting.mediaProperties.webrtcMediaConnection.setCodecParameters);
4100
4182
  });
4101
4183
  });
@@ -4301,7 +4383,8 @@ describe('plugin-meetings', () => {
4301
4383
 
4302
4384
  describe('submitClientEvent on connectionFailed', () => {
4303
4385
  it('sends client.ice.end when connectionFailed on CONNECTION_STATE_CHANGED event', () => {
4304
- webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode = sinon.stub().returns({})
4386
+ webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode =
4387
+ sinon.stub().returns({});
4305
4388
  meeting.setupMediaConnectionListeners();
4306
4389
  eventListeners[Event.CONNECTION_STATE_CHANGED]({
4307
4390
  state: 'Failed',
@@ -4625,7 +4708,7 @@ describe('plugin-meetings', () => {
4625
4708
  it('registers for audio and video source count changed', () => {
4626
4709
  assert.isFunction(eventListeners[Event.VIDEO_SOURCES_COUNT_CHANGED]);
4627
4710
  assert.isFunction(eventListeners[Event.AUDIO_SOURCES_COUNT_CHANGED]);
4628
- })
4711
+ });
4629
4712
 
4630
4713
  it('forwards the VIDEO_SOURCES_COUNT_CHANGED event as "media:remoteVideoSourceCountChanged"', () => {
4631
4714
  const numTotalSources = 10;
@@ -4634,9 +4717,14 @@ describe('plugin-meetings', () => {
4634
4717
 
4635
4718
  sinon.stub(meeting.mediaRequestManagers.video, 'setNumCurrentSources');
4636
4719
 
4637
- eventListeners[Event.VIDEO_SOURCES_COUNT_CHANGED](numTotalSources, numLiveSources, mediaContent);
4720
+ eventListeners[Event.VIDEO_SOURCES_COUNT_CHANGED](
4721
+ numTotalSources,
4722
+ numLiveSources,
4723
+ mediaContent
4724
+ );
4638
4725
 
4639
- assert.calledOnceWithExactly(TriggerProxy.trigger,
4726
+ assert.calledOnceWithExactly(
4727
+ TriggerProxy.trigger,
4640
4728
  meeting,
4641
4729
  sinon.match.object,
4642
4730
  'media:remoteVideoSourceCountChanged',
@@ -4653,9 +4741,14 @@ describe('plugin-meetings', () => {
4653
4741
  const numLiveSources = 2;
4654
4742
  const mediaContent = 'MAIN';
4655
4743
 
4656
- eventListeners[Event.AUDIO_SOURCES_COUNT_CHANGED](numTotalSources, numLiveSources, mediaContent);
4744
+ eventListeners[Event.AUDIO_SOURCES_COUNT_CHANGED](
4745
+ numTotalSources,
4746
+ numLiveSources,
4747
+ mediaContent
4748
+ );
4657
4749
 
4658
- assert.calledOnceWithExactly(TriggerProxy.trigger,
4750
+ assert.calledOnceWithExactly(
4751
+ TriggerProxy.trigger,
4659
4752
  meeting,
4660
4753
  sinon.match.object,
4661
4754
  'media:remoteAudioSourceCountChanged',
@@ -4671,9 +4764,16 @@ describe('plugin-meetings', () => {
4671
4764
  const numTotalSources = 20;
4672
4765
  const numLiveSources = 10;
4673
4766
 
4674
- const setNumCurrentSourcesSpy = sinon.stub(meeting.mediaRequestManagers.video, 'setNumCurrentSources');
4767
+ const setNumCurrentSourcesSpy = sinon.stub(
4768
+ meeting.mediaRequestManagers.video,
4769
+ 'setNumCurrentSources'
4770
+ );
4675
4771
 
4676
- eventListeners[Event.VIDEO_SOURCES_COUNT_CHANGED](numTotalSources, numLiveSources, 'MAIN');
4772
+ eventListeners[Event.VIDEO_SOURCES_COUNT_CHANGED](
4773
+ numTotalSources,
4774
+ numLiveSources,
4775
+ 'MAIN'
4776
+ );
4677
4777
 
4678
4778
  assert.calledOnceWithExactly(setNumCurrentSourcesSpy, numTotalSources, numLiveSources);
4679
4779
  });
@@ -4682,14 +4782,20 @@ describe('plugin-meetings', () => {
4682
4782
  const numTotalSources = 20;
4683
4783
  const numLiveSources = 10;
4684
4784
 
4685
- const setNumCurrentSourcesSpy = sinon.stub(meeting.mediaRequestManagers.video, 'setNumCurrentSources');
4785
+ const setNumCurrentSourcesSpy = sinon.stub(
4786
+ meeting.mediaRequestManagers.video,
4787
+ 'setNumCurrentSources'
4788
+ );
4686
4789
 
4687
- eventListeners[Event.VIDEO_SOURCES_COUNT_CHANGED](numTotalSources, numLiveSources, 'SLIDES');
4790
+ eventListeners[Event.VIDEO_SOURCES_COUNT_CHANGED](
4791
+ numTotalSources,
4792
+ numLiveSources,
4793
+ 'SLIDES'
4794
+ );
4688
4795
 
4689
4796
  assert.notCalled(setNumCurrentSourcesSpy);
4690
4797
  });
4691
-
4692
- })
4798
+ });
4693
4799
  });
4694
4800
  describe('#setUpLocusInfoSelfListener', () => {
4695
4801
  it('listens to the self unadmitted guest event', (done) => {
@@ -4746,14 +4852,13 @@ describe('plugin-meetings', () => {
4746
4852
  meeting.breakouts.updateCanManageBreakouts = sinon.stub();
4747
4853
  meeting.simultaneousInterpretation.updateCanManageInterpreters = sinon.stub();
4748
4854
 
4749
- meeting.locusInfo.emit(
4750
- {function: 'test', file: 'test'},
4751
- 'SELF_ROLES_CHANGED',
4752
- payload
4753
- );
4855
+ meeting.locusInfo.emit({function: 'test', file: 'test'}, 'SELF_ROLES_CHANGED', payload);
4754
4856
 
4755
4857
  assert.calledOnceWithExactly(meeting.breakouts.updateCanManageBreakouts, true);
4756
- assert.calledOnceWithExactly(meeting.simultaneousInterpretation.updateCanManageInterpreters, true);
4858
+ assert.calledOnceWithExactly(
4859
+ meeting.simultaneousInterpretation.updateCanManageInterpreters,
4860
+ true
4861
+ );
4757
4862
  assert.calledWith(
4758
4863
  TriggerProxy.trigger,
4759
4864
  meeting,
@@ -4774,7 +4879,10 @@ describe('plugin-meetings', () => {
4774
4879
  payload
4775
4880
  );
4776
4881
 
4777
- assert.calledOnceWithExactly(meeting.simultaneousInterpretation.updateSelfInterpretation, payload);
4882
+ assert.calledOnceWithExactly(
4883
+ meeting.simultaneousInterpretation.updateSelfInterpretation,
4884
+ payload
4885
+ );
4778
4886
  assert.calledWith(
4779
4887
  TriggerProxy.trigger,
4780
4888
  meeting,
@@ -4827,14 +4935,14 @@ describe('plugin-meetings', () => {
4827
4935
 
4828
4936
  it('should not trigger ASK_RETURN_TO_MAIN before joined', () => {
4829
4937
  TriggerProxy.trigger.reset();
4830
- meeting.joinedWith = {state: "NOT_JOINED"};
4938
+ meeting.joinedWith = {state: 'NOT_JOINED'};
4831
4939
  meeting.breakouts.trigger('ASK_RETURN_TO_MAIN');
4832
4940
  assert.notCalled(TriggerProxy.trigger);
4833
4941
  });
4834
4942
 
4835
4943
  it('listens to the ask return to main event from breakouts and triggers the ask return to main event from meeting', () => {
4836
4944
  TriggerProxy.trigger.reset();
4837
- meeting.joinedWith = {state: "JOINED"};
4945
+ meeting.joinedWith = {state: 'JOINED'};
4838
4946
  meeting.breakouts.trigger('ASK_RETURN_TO_MAIN');
4839
4947
  assert.calledWith(
4840
4948
  TriggerProxy.trigger,
@@ -4857,7 +4965,7 @@ describe('plugin-meetings', () => {
4857
4965
 
4858
4966
  it('listens to the breakout ask for help event and triggers the ask for help event', () => {
4859
4967
  TriggerProxy.trigger.reset();
4860
- const helpEvent = {sessionId:'sessionId', participant: 'participant'}
4968
+ const helpEvent = {sessionId: 'sessionId', participant: 'participant'};
4861
4969
  meeting.breakouts.trigger('ASK_FOR_HELP', helpEvent);
4862
4970
  assert.calledWith(
4863
4971
  TriggerProxy.trigger,
@@ -4904,7 +5012,7 @@ describe('plugin-meetings', () => {
4904
5012
  });
4905
5013
 
4906
5014
  it('listens to CONTROLS_MUTE_ON_ENTRY_CHANGED', async () => {
4907
- const state = {example: 'value'}
5015
+ const state = {example: 'value'};
4908
5016
 
4909
5017
  await meeting.locusInfo.emitScoped(
4910
5018
  {function: 'test', file: 'test'},
@@ -4917,12 +5025,12 @@ describe('plugin-meetings', () => {
4917
5025
  meeting,
4918
5026
  {file: 'meeting/index', function: 'setupLocusControlsListener'},
4919
5027
  EVENT_TRIGGERS.MEETING_CONTROLS_MUTE_ON_ENTRY_UPDATED,
4920
- {state},
5028
+ {state}
4921
5029
  );
4922
5030
  });
4923
5031
 
4924
5032
  it('listens to MEETING_CONTROLS_SHARE_CONTROL_UPDATED', async () => {
4925
- const state = {example: 'value'}
5033
+ const state = {example: 'value'};
4926
5034
 
4927
5035
  await meeting.locusInfo.emitScoped(
4928
5036
  {function: 'test', file: 'test'},
@@ -4935,12 +5043,12 @@ describe('plugin-meetings', () => {
4935
5043
  meeting,
4936
5044
  {file: 'meeting/index', function: 'setupLocusControlsListener'},
4937
5045
  EVENT_TRIGGERS.MEETING_CONTROLS_SHARE_CONTROL_UPDATED,
4938
- {state},
5046
+ {state}
4939
5047
  );
4940
5048
  });
4941
5049
 
4942
5050
  it('listens to MEETING_CONTROLS_DISALLOW_UNMUTE_UPDATED', async () => {
4943
- const state = {example: 'value'}
5051
+ const state = {example: 'value'};
4944
5052
 
4945
5053
  await meeting.locusInfo.emitScoped(
4946
5054
  {function: 'test', file: 'test'},
@@ -4953,12 +5061,12 @@ describe('plugin-meetings', () => {
4953
5061
  meeting,
4954
5062
  {file: 'meeting/index', function: 'setupLocusControlsListener'},
4955
5063
  EVENT_TRIGGERS.MEETING_CONTROLS_DISALLOW_UNMUTE_UPDATED,
4956
- {state},
5064
+ {state}
4957
5065
  );
4958
5066
  });
4959
5067
 
4960
5068
  it('listens to MEETING_CONTROLS_REACTIONS_UPDATED', async () => {
4961
- const state = {example: 'value'}
5069
+ const state = {example: 'value'};
4962
5070
 
4963
5071
  await meeting.locusInfo.emitScoped(
4964
5072
  {function: 'test', file: 'test'},
@@ -4971,12 +5079,12 @@ describe('plugin-meetings', () => {
4971
5079
  meeting,
4972
5080
  {file: 'meeting/index', function: 'setupLocusControlsListener'},
4973
5081
  EVENT_TRIGGERS.MEETING_CONTROLS_REACTIONS_UPDATED,
4974
- {state},
5082
+ {state}
4975
5083
  );
4976
5084
  });
4977
5085
 
4978
5086
  it('listens to MEETING_CONTROLS_VIEW_THE_PARTICIPANTS_LIST_UPDATED', async () => {
4979
- const state = {example: 'value'}
5087
+ const state = {example: 'value'};
4980
5088
 
4981
5089
  await meeting.locusInfo.emitScoped(
4982
5090
  {function: 'test', file: 'test'},
@@ -4989,12 +5097,12 @@ describe('plugin-meetings', () => {
4989
5097
  meeting,
4990
5098
  {file: 'meeting/index', function: 'setupLocusControlsListener'},
4991
5099
  EVENT_TRIGGERS.MEETING_CONTROLS_VIEW_THE_PARTICIPANTS_LIST_UPDATED,
4992
- {state},
5100
+ {state}
4993
5101
  );
4994
5102
  });
4995
5103
 
4996
5104
  it('listens to MEETING_CONTROLS_RAISE_HAND_UPDATED', async () => {
4997
- const state = {example: 'value'}
5105
+ const state = {example: 'value'};
4998
5106
 
4999
5107
  await meeting.locusInfo.emitScoped(
5000
5108
  {function: 'test', file: 'test'},
@@ -5007,12 +5115,12 @@ describe('plugin-meetings', () => {
5007
5115
  meeting,
5008
5116
  {file: 'meeting/index', function: 'setupLocusControlsListener'},
5009
5117
  EVENT_TRIGGERS.MEETING_CONTROLS_RAISE_HAND_UPDATED,
5010
- {state},
5118
+ {state}
5011
5119
  );
5012
5120
  });
5013
5121
 
5014
5122
  it('listens to MEETING_CONTROLS_VIDEO_UPDATED', async () => {
5015
- const state = {example: 'value'}
5123
+ const state = {example: 'value'};
5016
5124
 
5017
5125
  await meeting.locusInfo.emitScoped(
5018
5126
  {function: 'test', file: 'test'},
@@ -5025,7 +5133,7 @@ describe('plugin-meetings', () => {
5025
5133
  meeting,
5026
5134
  {file: 'meeting/index', function: 'setupLocusControlsListener'},
5027
5135
  EVENT_TRIGGERS.MEETING_CONTROLS_VIDEO_UPDATED,
5028
- {state},
5136
+ {state}
5029
5137
  );
5030
5138
  });
5031
5139
 
@@ -5076,7 +5184,10 @@ describe('plugin-meetings', () => {
5076
5184
  {interpretation}
5077
5185
  );
5078
5186
 
5079
- assert.calledOnceWithExactly(meeting.simultaneousInterpretation.updateInterpretation, interpretation);
5187
+ assert.calledOnceWithExactly(
5188
+ meeting.simultaneousInterpretation.updateInterpretation,
5189
+ interpretation
5190
+ );
5080
5191
  assert.calledWith(
5081
5192
  TriggerProxy.trigger,
5082
5193
  meeting,
@@ -5148,15 +5259,15 @@ describe('plugin-meetings', () => {
5148
5259
 
5149
5260
  assert.calledWith(
5150
5261
  meeting.recordingController.setServiceUrl,
5151
- newLocusServices.services.record.url,
5262
+ newLocusServices.services.record.url
5152
5263
  );
5153
5264
  assert.calledWith(
5154
5265
  meeting.annotation.approvalUrlUpdate,
5155
- newLocusServices.services.approval.url,
5266
+ newLocusServices.services.approval.url
5156
5267
  );
5157
5268
  assert.calledWith(
5158
5269
  meeting.simultaneousInterpretation.approvalUrlUpdate,
5159
- newLocusServices.services.approval.url,
5270
+ newLocusServices.services.approval.url
5160
5271
  );
5161
5272
  assert.calledOnce(meeting.recordingController.setSessionId);
5162
5273
  done();
@@ -5569,12 +5680,12 @@ describe('plugin-meetings', () => {
5569
5680
  currentSIInterpreter: false,
5570
5681
  siLanguages: [
5571
5682
  {
5572
- languageCode: "ar",
5683
+ languageCode: 'ar',
5573
5684
  languageGroupId: 4,
5574
5685
  },
5575
- ]
5576
- }
5577
- }
5686
+ ],
5687
+ },
5688
+ },
5578
5689
  };
5579
5690
  meeting.parseMeetingInfo(mockToggleOnData);
5580
5691
  assert.calledOnceWithExactly(parseInterpretationInfo, meeting, mockToggleOnData.body);
@@ -5693,7 +5804,6 @@ describe('plugin-meetings', () => {
5693
5804
  waitingForOthersToJoinSpy.restore();
5694
5805
  });
5695
5806
 
5696
-
5697
5807
  forEach(
5698
5808
  [
5699
5809
  {
@@ -5812,6 +5922,11 @@ describe('plugin-meetings', () => {
5812
5922
  requiredPolicies: [],
5813
5923
  enableUnifiedMeetings: false,
5814
5924
  },
5925
+ {
5926
+ actionName: 'canAnnotate',
5927
+ requiredDisplayHints: [],
5928
+ requiredPolicies: [SELF_POLICY.SUPPORT_ANNOTATION],
5929
+ },
5815
5930
  ],
5816
5931
  ({actionName, requiredDisplayHints, requiredPolicies, enableUnifiedMeetings}) => {
5817
5932
  it(`${actionName} is enabled when the conditions are met`, () => {
@@ -6125,7 +6240,6 @@ describe('plugin-meetings', () => {
6125
6240
  meeting.joinedWith = {state: 'JOINED'};
6126
6241
  meeting.locusInfo = {url: 'a url', info: {datachannelUrl: 'a datachannel url'}};
6127
6242
 
6128
-
6129
6243
  const result = await meeting.updateLLMConnection();
6130
6244
 
6131
6245
  assert.notCalled(webex.internal.llm.disconnectLLM);
@@ -6164,9 +6278,7 @@ describe('plugin-meetings', () => {
6164
6278
  'event:relay.event',
6165
6279
  meeting.processRelayEvent
6166
6280
  );
6167
- assert.calledTwice(
6168
- meeting.webex.internal.llm.off
6169
- );
6281
+ assert.calledTwice(meeting.webex.internal.llm.off);
6170
6282
  assert.calledOnceWithExactly(
6171
6283
  meeting.webex.internal.llm.on,
6172
6284
  'event:relay.event',
@@ -6192,7 +6304,6 @@ describe('plugin-meetings', () => {
6192
6304
  meeting.processRelayEvent
6193
6305
  );
6194
6306
  });
6195
-
6196
6307
  });
6197
6308
 
6198
6309
  describe('#setLocus', () => {
@@ -6293,15 +6404,13 @@ describe('plugin-meetings', () => {
6293
6404
  });
6294
6405
  });
6295
6406
  describe('share scenarios', () => {
6296
-
6297
6407
  describe('triggerAnnotationInfoEvent', () => {
6298
6408
  it('check triggerAnnotationInfoEvent event', () => {
6299
-
6300
6409
  TriggerProxy.trigger.reset();
6301
- const annotationInfo= {version: '1', policy: 'Approval'}
6302
- const expectAnnotationInfo = {annotationInfo,meetingId:meeting.id };
6303
- meeting.webex.meetings ={}
6304
- meeting.triggerAnnotationInfoEvent({annotation:annotationInfo},{});
6410
+ const annotationInfo = {version: '1', policy: 'Approval'};
6411
+ const expectAnnotationInfo = {annotationInfo, meetingId: meeting.id};
6412
+ meeting.webex.meetings = {};
6413
+ meeting.triggerAnnotationInfoEvent({annotation: annotationInfo}, {});
6305
6414
  assert.calledWith(
6306
6415
  TriggerProxy.trigger,
6307
6416
  {},
@@ -6314,13 +6423,22 @@ describe('plugin-meetings', () => {
6314
6423
  );
6315
6424
 
6316
6425
  TriggerProxy.trigger.reset();
6317
- meeting.triggerAnnotationInfoEvent({annotation:annotationInfo},{annotation:annotationInfo});
6426
+ meeting.triggerAnnotationInfoEvent(
6427
+ {annotation: annotationInfo},
6428
+ {annotation: annotationInfo}
6429
+ );
6318
6430
  assert.notCalled(TriggerProxy.trigger);
6319
6431
 
6320
6432
  TriggerProxy.trigger.reset();
6321
- const annotationInfoUpdate = {version: '1', policy: 'AnnotationNotAllowed'}
6322
- const expectAnnotationInfoUpdated = { annotationInfo: annotationInfoUpdate, meetingId:meeting.id };
6323
- meeting.triggerAnnotationInfoEvent({annotation: annotationInfoUpdate},{annotation:annotationInfo});
6433
+ const annotationInfoUpdate = {version: '1', policy: 'AnnotationNotAllowed'};
6434
+ const expectAnnotationInfoUpdated = {
6435
+ annotationInfo: annotationInfoUpdate,
6436
+ meetingId: meeting.id,
6437
+ };
6438
+ meeting.triggerAnnotationInfoEvent(
6439
+ {annotation: annotationInfoUpdate},
6440
+ {annotation: annotationInfo}
6441
+ );
6324
6442
  assert.calledWith(
6325
6443
  TriggerProxy.trigger,
6326
6444
  {},
@@ -6333,9 +6451,8 @@ describe('plugin-meetings', () => {
6333
6451
  );
6334
6452
 
6335
6453
  TriggerProxy.trigger.reset();
6336
- meeting.triggerAnnotationInfoEvent(null,{annotation:annotationInfoUpdate});
6454
+ meeting.triggerAnnotationInfoEvent(null, {annotation: annotationInfoUpdate});
6337
6455
  assert.notCalled(TriggerProxy.trigger);
6338
-
6339
6456
  });
6340
6457
  });
6341
6458
 
@@ -6357,7 +6474,11 @@ describe('plugin-meetings', () => {
6357
6474
  'https://board-a.wbx2.com/board/api/v1/channels/977a7330-54f4-11eb-b1ef-91f5eefc7bf3',
6358
6475
  };
6359
6476
 
6360
- const generateContent = (beneficiaryId = null, disposition = null,annotation = undefined) => ({
6477
+ const generateContent = (
6478
+ beneficiaryId = null,
6479
+ disposition = null,
6480
+ annotation = undefined
6481
+ ) => ({
6361
6482
  beneficiaryId,
6362
6483
  disposition,
6363
6484
  });
@@ -6403,7 +6524,11 @@ describe('plugin-meetings', () => {
6403
6524
  if (isGranting) {
6404
6525
  if (isContent) {
6405
6526
  activeSharingId.content = beneficiaryId;
6406
- newPayload.current.content = generateContent(beneficiaryId, FLOOR_ACTION.GRANTED,annotation);
6527
+ newPayload.current.content = generateContent(
6528
+ beneficiaryId,
6529
+ FLOOR_ACTION.GRANTED,
6530
+ annotation
6531
+ );
6407
6532
 
6408
6533
  if (isEqual(newPayload.current, newPayload.previous)) {
6409
6534
  eventTrigger.member = null;
@@ -6457,7 +6582,12 @@ describe('plugin-meetings', () => {
6457
6582
  eventTrigger.share.push({
6458
6583
  eventName: EVENT_TRIGGERS.MEETING_STARTED_SHARING_REMOTE,
6459
6584
  functionName: 'remoteShare',
6460
- eventPayload: {memberId: beneficiaryId, url, shareInstanceId , annotationInfo:undefined},
6585
+ eventPayload: {
6586
+ memberId: beneficiaryId,
6587
+ url,
6588
+ shareInstanceId,
6589
+ annotationInfo: undefined,
6590
+ },
6461
6591
  });
6462
6592
  }
6463
6593
  }