@webex/plugin-meetings 2.60.1-next.7 → 2.60.1-next.8

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.
Files changed (54) hide show
  1. package/README.md +12 -0
  2. package/dist/breakouts/breakout.js +1 -1
  3. package/dist/breakouts/index.js +1 -1
  4. package/dist/constants.d.ts +12 -2
  5. package/dist/constants.js +15 -5
  6. package/dist/constants.js.map +1 -1
  7. package/dist/interpretation/index.js +1 -1
  8. package/dist/interpretation/siLanguage.js +1 -1
  9. package/dist/locus-info/index.d.ts +1 -1
  10. package/dist/locus-info/index.js +8 -8
  11. package/dist/locus-info/index.js.map +1 -1
  12. package/dist/meeting/index.d.ts +62 -18
  13. package/dist/meeting/index.js +679 -568
  14. package/dist/meeting/index.js.map +1 -1
  15. package/dist/meeting/request.js +25 -18
  16. package/dist/meeting/request.js.map +1 -1
  17. package/dist/meeting/util.d.ts +16 -0
  18. package/dist/meeting/util.js +71 -0
  19. package/dist/meeting/util.js.map +1 -1
  20. package/dist/meetings/index.d.ts +25 -3
  21. package/dist/meetings/index.js +83 -32
  22. package/dist/meetings/index.js.map +1 -1
  23. package/dist/reachability/index.js +11 -6
  24. package/dist/reachability/index.js.map +1 -1
  25. package/dist/reconnection-manager/index.js +3 -1
  26. package/dist/reconnection-manager/index.js.map +1 -1
  27. package/dist/roap/index.js +50 -54
  28. package/dist/roap/index.js.map +1 -1
  29. package/dist/statsAnalyzer/index.js +1 -1
  30. package/dist/statsAnalyzer/index.js.map +1 -1
  31. package/dist/statsAnalyzer/mqaUtil.js +13 -10
  32. package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
  33. package/dist/webinar/index.js +1 -1
  34. package/package.json +22 -22
  35. package/src/constants.ts +13 -2
  36. package/src/locus-info/index.ts +13 -12
  37. package/src/meeting/index.ts +215 -116
  38. package/src/meeting/request.ts +7 -0
  39. package/src/meeting/util.ts +97 -0
  40. package/src/meetings/index.ts +59 -18
  41. package/src/reachability/index.ts +7 -4
  42. package/src/reconnection-manager/index.ts +1 -1
  43. package/src/roap/index.ts +49 -51
  44. package/src/statsAnalyzer/index.ts +2 -2
  45. package/src/statsAnalyzer/mqaUtil.ts +15 -14
  46. package/test/unit/spec/locus-info/index.js +53 -5
  47. package/test/unit/spec/meeting/index.js +1792 -1139
  48. package/test/unit/spec/meeting/request.js +22 -12
  49. package/test/unit/spec/meeting/utils.js +93 -0
  50. package/test/unit/spec/meetings/index.js +180 -21
  51. package/test/unit/spec/reachability/index.ts +2 -1
  52. package/test/unit/spec/reconnection-manager/index.js +1 -0
  53. package/test/unit/spec/roap/index.ts +28 -42
  54. package/test/unit/spec/stats-analyzer/index.js +415 -30
@@ -13,7 +13,7 @@ import {Credentials, Token, WebexPlugin} from '@webex/webex-core';
13
13
  import Support from '@webex/internal-plugin-support';
14
14
  import MockWebex from '@webex/test-helper-mock-webex';
15
15
  import StaticConfig from '@webex/plugin-meetings/src/common/config';
16
- import { Defer } from '@webex/common';
16
+ import {Defer} from '@webex/common';
17
17
  import {
18
18
  FLOOR_ACTION,
19
19
  SHARE_STATUS,
@@ -44,9 +44,7 @@ import {
44
44
  RemoteTrackType,
45
45
  MediaType,
46
46
  } from '@webex/internal-media-core';
47
- import {
48
- StreamEventNames,
49
- } from '@webex/media-helpers';
47
+ import {StreamEventNames} from '@webex/media-helpers';
50
48
  import * as StatsAnalyzerModule from '@webex/plugin-meetings/src/statsAnalyzer';
51
49
  import EventsScope from '@webex/plugin-meetings/src/common/events/events-scope';
52
50
  import Meetings, {CONSTANTS} from '@webex/plugin-meetings';
@@ -73,7 +71,7 @@ import BEHAVIORAL_METRICS from '@webex/plugin-meetings/src/metrics/constants';
73
71
  import {MediaRequestManager} from '@webex/plugin-meetings/src/multistream/mediaRequestManager';
74
72
  import * as ReceiveSlotManagerModule from '@webex/plugin-meetings/src/multistream/receiveSlotManager';
75
73
  import * as SendSlotManagerModule from '@webex/plugin-meetings/src/multistream/sendSlotManager';
76
- import { CallDiagnosticUtils } from '@webex/internal-plugin-metrics';
74
+ import {CallDiagnosticUtils} from '@webex/internal-plugin-metrics';
77
75
 
78
76
  import CallDiagnosticLatencies from '@webex/internal-plugin-metrics/src/call-diagnostic/call-diagnostic-metrics-latencies';
79
77
  import LLM from '@webex/internal-plugin-llm';
@@ -110,10 +108,9 @@ import {
110
108
  MISSING_ROAP_ANSWER_CLIENT_CODE,
111
109
  } from '@webex/internal-plugin-metrics/src/call-diagnostic/config';
112
110
  import CallDiagnosticMetrics from '@webex/internal-plugin-metrics/src/call-diagnostic/call-diagnostic-metrics';
113
- import { ERROR_DESCRIPTIONS } from '@webex/internal-plugin-metrics/src/call-diagnostic/config';
111
+ import {ERROR_DESCRIPTIONS} from '@webex/internal-plugin-metrics/src/call-diagnostic/config';
114
112
  import MeetingCollection from '@webex/plugin-meetings/src/meetings/collection';
115
113
 
116
-
117
114
  describe('plugin-meetings', () => {
118
115
  const logger = {
119
116
  info: () => {},
@@ -392,7 +389,7 @@ describe('plugin-meetings', () => {
392
389
  correlationId: uuid4,
393
390
  joinTrigger: 'fake-join-trigger',
394
391
  loginType: 'fake-login-type',
395
- }
392
+ },
396
393
  },
397
394
  {
398
395
  parent: webex,
@@ -495,8 +492,7 @@ describe('plugin-meetings', () => {
495
492
  let mockSendSlotManagerCtor;
496
493
 
497
494
  beforeEach(() => {
498
- mockSendSlotManagerCtor = sinon
499
- .stub(SendSlotManagerModule,'default');
495
+ mockSendSlotManagerCtor = sinon.stub(SendSlotManagerModule, 'default');
500
496
 
501
497
  meeting = new Meeting(
502
498
  {
@@ -868,7 +864,11 @@ describe('plugin-meetings', () => {
868
864
 
869
865
  assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
870
866
  name: 'client.call.initiated',
871
- payload: {trigger: 'user-interaction', isRoapCallEnabled: true, pstnAudioType: 'dial-in'},
867
+ payload: {
868
+ trigger: 'user-interaction',
869
+ isRoapCallEnabled: true,
870
+ pstnAudioType: 'dial-in',
871
+ },
872
872
  options: {meetingId: meeting.id},
873
873
  });
874
874
 
@@ -1041,22 +1041,23 @@ describe('plugin-meetings', () => {
1041
1041
 
1042
1042
  assert.equal(result, joinMeetingResult);
1043
1043
 
1044
- defer.reject(new Error("bad day", {cause: 'bad weather'}));
1044
+ defer.reject(new Error('bad day', {cause: 'bad weather'}));
1045
1045
 
1046
1046
  try {
1047
1047
  await defer.promise;
1048
1048
  } catch (err) {
1049
-
1050
1049
  assert.deepEqual(Metrics.sendBehavioralMetric.getCalls()[0].args, [
1051
- BEHAVIORAL_METRICS.JOIN_SUCCESS, {correlation_id: meeting.correlationId}
1052
- ])
1050
+ BEHAVIORAL_METRICS.JOIN_SUCCESS,
1051
+ {correlation_id: meeting.correlationId},
1052
+ ]);
1053
1053
 
1054
1054
  assert.deepEqual(Metrics.sendBehavioralMetric.getCalls()[1].args, [
1055
- BEHAVIORAL_METRICS.LLM_CONNECTION_AFTER_JOIN_FAILURE, {
1055
+ BEHAVIORAL_METRICS.LLM_CONNECTION_AFTER_JOIN_FAILURE,
1056
+ {
1056
1057
  correlation_id: meeting.correlationId,
1057
1058
  reason: err.message,
1058
1059
  stack: err.stack,
1059
- }
1060
+ },
1060
1061
  ]);
1061
1062
  }
1062
1063
  });
@@ -1094,25 +1095,27 @@ describe('plugin-meetings', () => {
1094
1095
 
1095
1096
  assert.equal(result, joinMeetingResult);
1096
1097
 
1097
- defer.reject(new Error("bad day", {cause: 'bad weather'}));
1098
+ defer.reject(new Error('bad day', {cause: 'bad weather'}));
1098
1099
 
1099
1100
  try {
1100
1101
  await defer.promise;
1101
1102
  } catch (err) {
1102
1103
  assert.deepEqual(Metrics.sendBehavioralMetric.getCalls()[0].args, [
1103
- BEHAVIORAL_METRICS.JOIN_SUCCESS, {correlation_id: meeting.correlationId}
1104
- ])
1104
+ BEHAVIORAL_METRICS.JOIN_SUCCESS,
1105
+ {correlation_id: meeting.correlationId},
1106
+ ]);
1105
1107
 
1106
1108
  assert.deepEqual(Metrics.sendBehavioralMetric.getCalls()[1].args, [
1107
- BEHAVIORAL_METRICS.RECEIVE_TRANSCRIPTION_AFTER_JOIN_FAILURE, {
1109
+ BEHAVIORAL_METRICS.RECEIVE_TRANSCRIPTION_AFTER_JOIN_FAILURE,
1110
+ {
1108
1111
  correlation_id: meeting.correlationId,
1109
1112
  reason: err.message,
1110
1113
  stack: err.stack,
1111
- }
1114
+ },
1112
1115
  ]);
1113
1116
  }
1114
- })
1115
- })
1117
+ });
1118
+ });
1116
1119
 
1117
1120
  describe('refreshPermissionToken', () => {
1118
1121
  it('should continue if permissionTokenRefresh fails with a generic error', async () => {
@@ -1123,14 +1126,20 @@ describe('plugin-meetings', () => {
1123
1126
  const result = await meeting.join();
1124
1127
  assert.notCalled(stateMachineFailSpy);
1125
1128
  assert.equal(result, joinMeetingResult);
1126
- assert.calledOnceWithExactly(meeting.checkAndRefreshPermissionToken, 30, 'ttl-join');
1129
+ assert.calledOnceWithExactly(
1130
+ meeting.checkAndRefreshPermissionToken,
1131
+ 30,
1132
+ 'ttl-join'
1133
+ );
1127
1134
  } catch (error) {
1128
1135
  assert.fail('join should not throw an Error');
1129
1136
  }
1130
- })
1137
+ });
1131
1138
 
1132
1139
  it('should throw if permissionTokenRefresh fails with a captcha error', async () => {
1133
- meeting.checkAndRefreshPermissionToken = sinon.stub().rejects(new CaptchaError('bad captcha'));
1140
+ meeting.checkAndRefreshPermissionToken = sinon
1141
+ .stub()
1142
+ .rejects(new CaptchaError('bad captcha'));
1134
1143
  const stateMachineFailSpy = sinon.spy(meeting.meetingFiniteStateMachine, 'fail');
1135
1144
  const joinMeetingOptionsSpy = sinon.spy(MeetingUtil, 'joinMeetingOptions');
1136
1145
 
@@ -1139,16 +1148,22 @@ describe('plugin-meetings', () => {
1139
1148
  assert.fail('join should have thrown a Captcha Error.');
1140
1149
  } catch (error) {
1141
1150
  assert.calledOnce(stateMachineFailSpy);
1142
- assert.calledOnceWithExactly(meeting.checkAndRefreshPermissionToken, 30, 'ttl-join');
1151
+ assert.calledOnceWithExactly(
1152
+ meeting.checkAndRefreshPermissionToken,
1153
+ 30,
1154
+ 'ttl-join'
1155
+ );
1143
1156
  assert.instanceOf(error, CaptchaError);
1144
1157
  assert.equal(error.message, 'bad captcha');
1145
1158
  // should not get to the end promise chain, which does do the join
1146
1159
  assert.notCalled(joinMeetingOptionsSpy);
1147
1160
  }
1148
- })
1161
+ });
1149
1162
 
1150
1163
  it('should throw if permissionTokenRefresh fails with a password error', async () => {
1151
- meeting.checkAndRefreshPermissionToken = sinon.stub().rejects(new PasswordError('bad password'));
1164
+ meeting.checkAndRefreshPermissionToken = sinon
1165
+ .stub()
1166
+ .rejects(new PasswordError('bad password'));
1152
1167
  const stateMachineFailSpy = sinon.spy(meeting.meetingFiniteStateMachine, 'fail');
1153
1168
  const joinMeetingOptionsSpy = sinon.spy(MeetingUtil.joinMeetingOptions);
1154
1169
 
@@ -1157,16 +1172,22 @@ describe('plugin-meetings', () => {
1157
1172
  assert.fail('join should have thrown a Password Error.');
1158
1173
  } catch (error) {
1159
1174
  assert.calledOnce(stateMachineFailSpy);
1160
- assert.calledOnceWithExactly(meeting.checkAndRefreshPermissionToken, 30, 'ttl-join');
1175
+ assert.calledOnceWithExactly(
1176
+ meeting.checkAndRefreshPermissionToken,
1177
+ 30,
1178
+ 'ttl-join'
1179
+ );
1161
1180
  assert.instanceOf(error, PasswordError);
1162
1181
  assert.equal(error.message, 'bad password');
1163
1182
  // should not get to the end promise chain, which does do the join
1164
1183
  assert.notCalled(joinMeetingOptionsSpy);
1165
1184
  }
1166
- })
1185
+ });
1167
1186
 
1168
1187
  it('should throw if permissionTokenRefresh fails with a permission error', async () => {
1169
- meeting.checkAndRefreshPermissionToken = sinon.stub().rejects(new PermissionError('bad permission'));
1188
+ meeting.checkAndRefreshPermissionToken = sinon
1189
+ .stub()
1190
+ .rejects(new PermissionError('bad permission'));
1170
1191
  const stateMachineFailSpy = sinon.spy(meeting.meetingFiniteStateMachine, 'fail');
1171
1192
  const joinMeetingOptionsSpy = sinon.spy(MeetingUtil.joinMeetingOptions);
1172
1193
 
@@ -1175,15 +1196,19 @@ describe('plugin-meetings', () => {
1175
1196
  assert.fail('join should have thrown a Permission Error.');
1176
1197
  } catch (error) {
1177
1198
  assert.calledOnce(stateMachineFailSpy);
1178
- assert.calledOnceWithExactly(meeting.checkAndRefreshPermissionToken, 30, 'ttl-join');
1199
+ assert.calledOnceWithExactly(
1200
+ meeting.checkAndRefreshPermissionToken,
1201
+ 30,
1202
+ 'ttl-join'
1203
+ );
1179
1204
  assert.instanceOf(error, PermissionError);
1180
1205
  assert.equal(error.message, 'bad permission');
1181
1206
  // should not get to the end promise chain, which does do the join
1182
1207
  assert.notCalled(joinMeetingOptionsSpy);
1183
1208
  }
1184
- })
1185
- })
1186
- })
1209
+ });
1210
+ });
1211
+ });
1187
1212
  });
1188
1213
 
1189
1214
  describe('#addMedia', () => {
@@ -1253,7 +1278,7 @@ describe('plugin-meetings', () => {
1253
1278
  meeting.webex.meetings.reachability = {
1254
1279
  getReachabilityMetrics: sinon.stub().resolves({
1255
1280
  someReachabilityMetric1: 'some value1',
1256
- someReachabilityMetric2: 'some value2'
1281
+ someReachabilityMetric2: 'some value2',
1257
1282
  }),
1258
1283
  };
1259
1284
 
@@ -1713,9 +1738,9 @@ describe('plugin-meetings', () => {
1713
1738
 
1714
1739
  it('should reject if waitForMediaConnectionConnected() rejects after turn server retry', async () => {
1715
1740
  const FAKE_ERROR = {fatal: true};
1716
- const getErrorPayloadForClientErrorCodeStub = webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode = sinon
1717
- .stub()
1718
- .returns(FAKE_ERROR);
1741
+ const getErrorPayloadForClientErrorCodeStub =
1742
+ (webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode =
1743
+ sinon.stub().returns(FAKE_ERROR));
1719
1744
  const MOCK_CLIENT_ERROR_CODE = 2004;
1720
1745
  const generateClientErrorCodeForIceFailureStub = sinon
1721
1746
  .stub(CallDiagnosticUtils, 'generateClientErrorCodeForIceFailure')
@@ -1726,17 +1751,22 @@ describe('plugin-meetings', () => {
1726
1751
  let errorThrown = undefined;
1727
1752
 
1728
1753
  // Stub doTurnDiscovery so that on the first call we skip turn discovery
1729
- meeting.roap.doTurnDiscovery = sinon.stub().onFirstCall().returns({
1730
- turnServerInfo: undefined,
1731
- turnDiscoverySkippedReason: 'reachability',
1732
- }).onSecondCall().returns({
1733
- turnServerInfo: {
1734
- url: FAKE_TURN_URL,
1735
- username: FAKE_TURN_USER,
1736
- password: FAKE_TURN_PASSWORD,
1737
- },
1738
- turnDiscoverySkippedReason: undefined,
1739
- });
1754
+ meeting.roap.doTurnDiscovery = sinon
1755
+ .stub()
1756
+ .onFirstCall()
1757
+ .returns({
1758
+ turnServerInfo: undefined,
1759
+ turnDiscoverySkippedReason: 'reachability',
1760
+ })
1761
+ .onSecondCall()
1762
+ .returns({
1763
+ turnServerInfo: {
1764
+ url: FAKE_TURN_URL,
1765
+ username: FAKE_TURN_USER,
1766
+ password: FAKE_TURN_PASSWORD,
1767
+ },
1768
+ turnDiscoverySkippedReason: undefined,
1769
+ });
1740
1770
  meeting.meetingState = 'ACTIVE';
1741
1771
  meeting.mediaProperties.waitForMediaConnectionConnected.rejects(new Error('fake error'));
1742
1772
 
@@ -1764,18 +1794,20 @@ describe('plugin-meetings', () => {
1764
1794
  signalingState: 'unknown',
1765
1795
  iceConnectionState: 'unknown',
1766
1796
  turnServerUsed: false,
1767
- })
1797
+ });
1768
1798
  assert.calledWith(generateClientErrorCodeForIceFailureStub, {
1769
1799
  signalingState: 'unknown',
1770
1800
  iceConnectionState: 'unknown',
1771
1801
  turnServerUsed: true,
1772
- })
1802
+ });
1773
1803
 
1774
1804
  assert.calledTwice(getErrorPayloadForClientErrorCodeStub);
1775
- assert.alwaysCalledWithExactly(getErrorPayloadForClientErrorCodeStub, {clientErrorCode: MOCK_CLIENT_ERROR_CODE});
1805
+ assert.alwaysCalledWithExactly(getErrorPayloadForClientErrorCodeStub, {
1806
+ clientErrorCode: MOCK_CLIENT_ERROR_CODE,
1807
+ });
1776
1808
 
1777
1809
  assert.calledThrice(webex.internal.newMetrics.submitClientEvent);
1778
- assert.calledWith(webex.internal.newMetrics.submitClientEvent.firstCall, {
1810
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent.firstCall, {
1779
1811
  name: 'client.media.capabilities',
1780
1812
  payload: {
1781
1813
  mediaCapabilities: {
@@ -1825,18 +1857,26 @@ describe('plugin-meetings', () => {
1825
1857
  // Turn discovery internal events are sent twice this time as we go through establishMediaConnection a second time on the retry
1826
1858
  const submitInternalEventCalls = webex.internal.newMetrics.submitInternalEvent.getCalls();
1827
1859
  assert.equal(submitInternalEventCalls.length, 4);
1828
- assert.deepEqual(submitInternalEventCalls[0].args, [{
1829
- name: 'internal.client.add-media.turn-discovery.start',
1830
- }]);
1831
- assert.deepEqual(submitInternalEventCalls[1].args, [{
1832
- name: 'internal.client.add-media.turn-discovery.end',
1833
- }]);
1834
- assert.deepEqual(submitInternalEventCalls[2].args, [{
1835
- name: 'internal.client.add-media.turn-discovery.start',
1836
- }]);
1837
- assert.deepEqual(submitInternalEventCalls[3].args, [{
1838
- name: 'internal.client.add-media.turn-discovery.end',
1839
- }]);
1860
+ assert.deepEqual(submitInternalEventCalls[0].args, [
1861
+ {
1862
+ name: 'internal.client.add-media.turn-discovery.start',
1863
+ },
1864
+ ]);
1865
+ assert.deepEqual(submitInternalEventCalls[1].args, [
1866
+ {
1867
+ name: 'internal.client.add-media.turn-discovery.end',
1868
+ },
1869
+ ]);
1870
+ assert.deepEqual(submitInternalEventCalls[2].args, [
1871
+ {
1872
+ name: 'internal.client.add-media.turn-discovery.start',
1873
+ },
1874
+ ]);
1875
+ assert.deepEqual(submitInternalEventCalls[3].args, [
1876
+ {
1877
+ name: 'internal.client.add-media.turn-discovery.end',
1878
+ },
1879
+ ]);
1840
1880
 
1841
1881
  const sendBehavioralMetricCalls = Metrics.sendBehavioralMetric.getCalls();
1842
1882
  assert.equal(sendBehavioralMetricCalls.length, 3);
@@ -1879,16 +1919,8 @@ describe('plugin-meetings', () => {
1879
1919
  // Check that doTurnDiscovery is called with th4 correct value of isForced
1880
1920
  const doTurnDiscoveryCalls = meeting.roap.doTurnDiscovery.getCalls();
1881
1921
  assert.equal(doTurnDiscoveryCalls.length, 2);
1882
- assert.deepEqual(doTurnDiscoveryCalls[0].args, [
1883
- meeting,
1884
- false,
1885
- false
1886
- ]);
1887
- assert.deepEqual(doTurnDiscoveryCalls[1].args, [
1888
- meeting,
1889
- true,
1890
- true
1891
- ]);
1922
+ assert.deepEqual(doTurnDiscoveryCalls[0].args, [meeting, false, false]);
1923
+ assert.deepEqual(doTurnDiscoveryCalls[1].args, [meeting, true, true]);
1892
1924
 
1893
1925
  // Some clean up steps happens twice
1894
1926
  assert.calledTwice(forceRtcMetricsSend);
@@ -1900,9 +1932,9 @@ describe('plugin-meetings', () => {
1900
1932
 
1901
1933
  it('should resolve if waitForMediaConnectionConnected() rejects the first time but resolves the second time', async () => {
1902
1934
  const FAKE_ERROR = {fatal: true};
1903
- const getErrorPayloadForClientErrorCodeStub = webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode = sinon
1904
- .stub()
1905
- .returns(FAKE_ERROR);
1935
+ const getErrorPayloadForClientErrorCodeStub =
1936
+ (webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode =
1937
+ sinon.stub().returns(FAKE_ERROR));
1906
1938
  const MOCK_CLIENT_ERROR_CODE = 2004;
1907
1939
  const generateClientErrorCodeForIceFailureStub = sinon
1908
1940
  .stub(CallDiagnosticUtils, 'generateClientErrorCodeForIceFailure')
@@ -1913,18 +1945,28 @@ describe('plugin-meetings', () => {
1913
1945
  let errorThrown = undefined;
1914
1946
 
1915
1947
  meeting.meetingState = 'ACTIVE';
1916
- meeting.roap.doTurnDiscovery = sinon.stub().onFirstCall().returns({
1917
- turnServerInfo: undefined,
1918
- turnDiscoverySkippedReason: 'reachability',
1919
- }).onSecondCall().returns({
1920
- turnServerInfo: {
1921
- url: FAKE_TURN_URL,
1922
- username: FAKE_TURN_USER,
1923
- password: FAKE_TURN_PASSWORD,
1924
- },
1925
- turnDiscoverySkippedReason: undefined,
1926
- });
1927
- meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().onFirstCall().rejects().onSecondCall().resolves();
1948
+ meeting.roap.doTurnDiscovery = sinon
1949
+ .stub()
1950
+ .onFirstCall()
1951
+ .returns({
1952
+ turnServerInfo: undefined,
1953
+ turnDiscoverySkippedReason: 'reachability',
1954
+ })
1955
+ .onSecondCall()
1956
+ .returns({
1957
+ turnServerInfo: {
1958
+ url: FAKE_TURN_URL,
1959
+ username: FAKE_TURN_USER,
1960
+ password: FAKE_TURN_PASSWORD,
1961
+ },
1962
+ turnDiscoverySkippedReason: undefined,
1963
+ });
1964
+ meeting.mediaProperties.waitForMediaConnectionConnected = sinon
1965
+ .stub()
1966
+ .onFirstCall()
1967
+ .rejects()
1968
+ .onSecondCall()
1969
+ .resolves();
1928
1970
 
1929
1971
  const forceRtcMetricsSend = sinon.stub().resolves();
1930
1972
  const closeMediaConnectionStub = sinon.stub();
@@ -1949,10 +1991,12 @@ describe('plugin-meetings', () => {
1949
1991
  signalingState: 'unknown',
1950
1992
  iceConnectionState: 'unknown',
1951
1993
  turnServerUsed: false,
1952
- })
1994
+ });
1953
1995
 
1954
1996
  assert.calledOnce(getErrorPayloadForClientErrorCodeStub);
1955
- assert.calledWith(getErrorPayloadForClientErrorCodeStub, {clientErrorCode: MOCK_CLIENT_ERROR_CODE});
1997
+ assert.calledWith(getErrorPayloadForClientErrorCodeStub, {
1998
+ clientErrorCode: MOCK_CLIENT_ERROR_CODE,
1999
+ });
1956
2000
 
1957
2001
  assert.calledThrice(webex.internal.newMetrics.submitClientEvent);
1958
2002
  assert.calledWith(webex.internal.newMetrics.submitClientEvent.firstCall, {
@@ -2000,18 +2044,26 @@ describe('plugin-meetings', () => {
2000
2044
  // Turn discovery internal events are sent twice this time as we go through establishMediaConnection a second time on the retry
2001
2045
  const submitInternalEventCalls = webex.internal.newMetrics.submitInternalEvent.getCalls();
2002
2046
  assert.equal(submitInternalEventCalls.length, 4);
2003
- assert.deepEqual(submitInternalEventCalls[0].args, [{
2004
- name: 'internal.client.add-media.turn-discovery.start',
2005
- }]);
2006
- assert.deepEqual(submitInternalEventCalls[1].args, [{
2007
- name: 'internal.client.add-media.turn-discovery.end',
2008
- }]);
2009
- assert.deepEqual(submitInternalEventCalls[2].args, [{
2010
- name: 'internal.client.add-media.turn-discovery.start',
2011
- }]);
2012
- assert.deepEqual(submitInternalEventCalls[3].args, [{
2013
- name: 'internal.client.add-media.turn-discovery.end',
2014
- }]);
2047
+ assert.deepEqual(submitInternalEventCalls[0].args, [
2048
+ {
2049
+ name: 'internal.client.add-media.turn-discovery.start',
2050
+ },
2051
+ ]);
2052
+ assert.deepEqual(submitInternalEventCalls[1].args, [
2053
+ {
2054
+ name: 'internal.client.add-media.turn-discovery.end',
2055
+ },
2056
+ ]);
2057
+ assert.deepEqual(submitInternalEventCalls[2].args, [
2058
+ {
2059
+ name: 'internal.client.add-media.turn-discovery.start',
2060
+ },
2061
+ ]);
2062
+ assert.deepEqual(submitInternalEventCalls[3].args, [
2063
+ {
2064
+ name: 'internal.client.add-media.turn-discovery.end',
2065
+ },
2066
+ ]);
2015
2067
 
2016
2068
  const sendBehavioralMetricCalls = Metrics.sendBehavioralMetric.getCalls();
2017
2069
  assert.equal(sendBehavioralMetricCalls.length, 3);
@@ -2043,21 +2095,13 @@ describe('plugin-meetings', () => {
2043
2095
  retriedWithTurnServer: true,
2044
2096
  },
2045
2097
  ]);
2046
- meeting.roap.doTurnDiscovery
2098
+ meeting.roap.doTurnDiscovery;
2047
2099
 
2048
2100
  // Check that doTurnDiscovery is called with th4 correct value of isForced
2049
2101
  const doTurnDiscoveryCalls = meeting.roap.doTurnDiscovery.getCalls();
2050
2102
  assert.equal(doTurnDiscoveryCalls.length, 2);
2051
- assert.deepEqual(doTurnDiscoveryCalls[0].args, [
2052
- meeting,
2053
- false,
2054
- false
2055
- ]);
2056
- assert.deepEqual(doTurnDiscoveryCalls[1].args, [
2057
- meeting,
2058
- true,
2059
- true
2060
- ]);
2103
+ assert.deepEqual(doTurnDiscoveryCalls[0].args, [meeting, false, false]);
2104
+ assert.deepEqual(doTurnDiscoveryCalls[1].args, [meeting, true, true]);
2061
2105
 
2062
2106
  assert.calledOnce(forceRtcMetricsSend);
2063
2107
  assert.calledOnce(closeMediaConnectionStub);
@@ -2073,18 +2117,28 @@ describe('plugin-meetings', () => {
2073
2117
 
2074
2118
  meeting.meetingState = 'ACTIVE';
2075
2119
  meeting.state = 'LEFT';
2076
- meeting.roap.doTurnDiscovery = sinon.stub().onFirstCall().returns({
2077
- turnServerInfo: undefined,
2078
- turnDiscoverySkippedReason: 'reachability',
2079
- }).onSecondCall().returns({
2080
- turnServerInfo: {
2081
- url: FAKE_TURN_URL,
2082
- username: FAKE_TURN_USER,
2083
- password: FAKE_TURN_PASSWORD,
2084
- },
2085
- turnDiscoverySkippedReason: undefined,
2086
- });
2087
- meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().onFirstCall().rejects().onSecondCall().resolves();
2120
+ meeting.roap.doTurnDiscovery = sinon
2121
+ .stub()
2122
+ .onFirstCall()
2123
+ .returns({
2124
+ turnServerInfo: undefined,
2125
+ turnDiscoverySkippedReason: 'reachability',
2126
+ })
2127
+ .onSecondCall()
2128
+ .returns({
2129
+ turnServerInfo: {
2130
+ url: FAKE_TURN_URL,
2131
+ username: FAKE_TURN_USER,
2132
+ password: FAKE_TURN_PASSWORD,
2133
+ },
2134
+ turnDiscoverySkippedReason: undefined,
2135
+ });
2136
+ meeting.mediaProperties.waitForMediaConnectionConnected = sinon
2137
+ .stub()
2138
+ .onFirstCall()
2139
+ .rejects()
2140
+ .onSecondCall()
2141
+ .resolves();
2088
2142
  meeting.join = sinon.stub().resolves();
2089
2143
 
2090
2144
  const closeMediaConnectionStub = sinon.stub();
@@ -2115,18 +2169,28 @@ describe('plugin-meetings', () => {
2115
2169
 
2116
2170
  meeting.meetingState = 'ACTIVE';
2117
2171
  meeting.state = 'LEFT';
2118
- meeting.roap.doTurnDiscovery = sinon.stub().onFirstCall().returns({
2119
- turnServerInfo: undefined,
2120
- turnDiscoverySkippedReason: 'reachability',
2121
- }).onSecondCall().returns({
2122
- turnServerInfo: {
2123
- url: FAKE_TURN_URL,
2124
- username: FAKE_TURN_USER,
2125
- password: FAKE_TURN_PASSWORD,
2126
- },
2127
- turnDiscoverySkippedReason: undefined,
2128
- });
2129
- meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().onFirstCall().rejects().onSecondCall().resolves();
2172
+ meeting.roap.doTurnDiscovery = sinon
2173
+ .stub()
2174
+ .onFirstCall()
2175
+ .returns({
2176
+ turnServerInfo: undefined,
2177
+ turnDiscoverySkippedReason: 'reachability',
2178
+ })
2179
+ .onSecondCall()
2180
+ .returns({
2181
+ turnServerInfo: {
2182
+ url: FAKE_TURN_URL,
2183
+ username: FAKE_TURN_USER,
2184
+ password: FAKE_TURN_PASSWORD,
2185
+ },
2186
+ turnDiscoverySkippedReason: undefined,
2187
+ });
2188
+ meeting.mediaProperties.waitForMediaConnectionConnected = sinon
2189
+ .stub()
2190
+ .onFirstCall()
2191
+ .rejects()
2192
+ .onSecondCall()
2193
+ .resolves();
2130
2194
  meeting.join = sinon.stub().rejects();
2131
2195
 
2132
2196
  const closeMediaConnectionStub = sinon.stub();
@@ -2154,7 +2218,7 @@ describe('plugin-meetings', () => {
2154
2218
  meeting.webex.meetings.reachability = {
2155
2219
  getReachabilityMetrics: sinon.stub().resolves({
2156
2220
  someReachabilityMetric1: 'some value1',
2157
- someReachabilityMetric2: 'some value2'
2221
+ someReachabilityMetric2: 'some value2',
2158
2222
  }),
2159
2223
  };
2160
2224
  await meeting.addMedia({
@@ -2216,7 +2280,8 @@ describe('plugin-meetings', () => {
2216
2280
  });
2217
2281
 
2218
2282
  // Check that the only metric sent is ADD_MEDIA_FAILURE
2219
- assert.calledOnceWithExactly(Metrics.sendBehavioralMetric,
2283
+ assert.calledOnceWithExactly(
2284
+ Metrics.sendBehavioralMetric,
2220
2285
  BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE,
2221
2286
  {
2222
2287
  correlation_id: meeting.correlationId,
@@ -2556,550 +2621,609 @@ describe('plugin-meetings', () => {
2556
2621
  to @webex/internal-media-core when addMedia, updateMedia, publishTracks, unpublishTracks are called
2557
2622
  in various combinations.
2558
2623
  */
2559
- [true,false].forEach((isMultistream) =>
2560
- describe(`addMedia/updateMedia semi-integration tests (${isMultistream ? 'multistream' : 'transcoded'})`, () => {
2561
- let fakeMicrophoneStream;
2562
- let fakeRoapMediaConnection;
2563
- let fakeMultistreamRoapMediaConnection;
2564
- let roapMediaConnectionConstructorStub;
2565
- let multistreamRoapMediaConnectionConstructorStub;
2566
- let locusMediaRequestStub; // stub for /media requests to Locus
2624
+ [true, false].forEach((isMultistream) =>
2625
+ describe(`addMedia/updateMedia semi-integration tests (${
2626
+ isMultistream ? 'multistream' : 'transcoded'
2627
+ })`, () => {
2628
+ let fakeMicrophoneStream;
2629
+ let fakeRoapMediaConnection;
2630
+ let fakeMultistreamRoapMediaConnection;
2631
+ let roapMediaConnectionConstructorStub;
2632
+ let multistreamRoapMediaConnectionConstructorStub;
2633
+ let locusMediaRequestStub; // stub for /media requests to Locus
2567
2634
 
2568
- const roapOfferMessage = {messageType: 'OFFER', sdp: 'sdp', seq: '1', tieBreaker: '123'};
2569
- const roapOKMessage = {messageType: 'OK', seq: '1'};
2635
+ const roapOfferMessage = {messageType: 'OFFER', sdp: 'sdp', seq: '1', tieBreaker: '123'};
2636
+ const roapOKMessage = {messageType: 'OK', seq: '1'};
2570
2637
 
2571
- let expectedMediaConnectionConfig;
2572
- let expectedDebugId;
2638
+ let expectedMediaConnectionConfig;
2639
+ let expectedDebugId;
2573
2640
 
2574
- let clock;
2641
+ let clock;
2575
2642
 
2576
- beforeEach(() => {
2577
- clock = sinon.useFakeTimers();
2643
+ beforeEach(() => {
2644
+ clock = sinon.useFakeTimers();
2578
2645
 
2579
- sinon.stub(MeetingUtil, 'getIpVersion').returns(IP_VERSION.unknown);
2646
+ sinon.stub(MeetingUtil, 'getIpVersion').returns(IP_VERSION.unknown);
2580
2647
 
2581
- meeting.deviceUrl = 'deviceUrl';
2582
- meeting.config.deviceType = 'web';
2583
- meeting.isMultistream = isMultistream;
2584
- meeting.meetingState = 'ACTIVE';
2585
- meeting.mediaId = 'fake media id';
2586
- meeting.selfUrl = 'selfUrl';
2587
- meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().resolves();
2588
- meeting.mediaProperties.getCurrentConnectionType = sinon.stub().resolves('udp');
2589
- meeting.setMercuryListener = sinon.stub();
2590
- meeting.locusInfo.onFullLocus = sinon.stub();
2591
- meeting.webex.meetings.geoHintInfo = {regionCode: 'EU', countryCode: 'UK'};
2592
- meeting.roap.doTurnDiscovery = sinon
2593
- .stub()
2594
- .resolves({turnServerInfo: {}, turnDiscoverySkippedReason: 'reachability'});
2595
- meeting.deferSDPAnswer = new Defer();
2596
- meeting.deferSDPAnswer.resolve();
2597
- meeting.webex.meetings.meetingCollection = new MeetingCollection();
2598
- meeting.webex.meetings.meetingCollection.set(meeting);
2599
-
2600
- StaticConfig.set({bandwidth: {audio: 1234, video: 5678, startBitrate: 9876}});
2601
-
2602
- // setup things that are expected to be the same across all the tests and are actually irrelevant for these tests
2603
- expectedDebugId = `MC-${meeting.id.substring(0, 4)}`;
2604
- expectedMediaConnectionConfig = {
2605
- iceServers: [{urls: undefined, username: '', credential: ''}],
2606
- skipInactiveTransceivers: false,
2607
- requireH264: true,
2608
- sdpMunging: {
2609
- convertPort9to0: false,
2610
- addContentSlides: true,
2611
- bandwidthLimits: {
2612
- audio: StaticConfig.meetings.bandwidth.audio,
2613
- video: StaticConfig.meetings.bandwidth.video,
2614
- },
2615
- startBitrate: StaticConfig.meetings.bandwidth.startBitrate,
2616
- periodicKeyframes: 20,
2617
- disableExtmap: !meeting.config.enableExtmap,
2618
- disableRtx: !meeting.config.enableRtx,
2619
- },
2620
- };
2648
+ meeting.deviceUrl = 'deviceUrl';
2649
+ meeting.config.deviceType = 'web';
2650
+ meeting.isMultistream = isMultistream;
2651
+ meeting.meetingState = 'ACTIVE';
2652
+ meeting.mediaId = 'fake media id';
2653
+ meeting.selfUrl = 'selfUrl';
2654
+ meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().resolves();
2655
+ meeting.mediaProperties.getCurrentConnectionType = sinon.stub().resolves('udp');
2656
+ meeting.setMercuryListener = sinon.stub();
2657
+ meeting.locusInfo.onFullLocus = sinon.stub();
2658
+ meeting.webex.meetings.geoHintInfo = {regionCode: 'EU', countryCode: 'UK'};
2659
+ meeting.roap.doTurnDiscovery = sinon
2660
+ .stub()
2661
+ .resolves({turnServerInfo: {}, turnDiscoverySkippedReason: 'reachability'});
2662
+ meeting.deferSDPAnswer = new Defer();
2663
+ meeting.deferSDPAnswer.resolve();
2664
+ meeting.webex.meetings.meetingCollection = new MeetingCollection();
2665
+ meeting.webex.meetings.meetingCollection.set(meeting);
2666
+
2667
+ StaticConfig.set({bandwidth: {audio: 1234, video: 5678, startBitrate: 9876}});
2668
+
2669
+ // setup things that are expected to be the same across all the tests and are actually irrelevant for these tests
2670
+ expectedDebugId = `MC-${meeting.id.substring(0, 4)}`;
2671
+ expectedMediaConnectionConfig = {
2672
+ iceServers: [{urls: undefined, username: '', credential: ''}],
2673
+ skipInactiveTransceivers: false,
2674
+ requireH264: true,
2675
+ sdpMunging: {
2676
+ convertPort9to0: false,
2677
+ addContentSlides: true,
2678
+ bandwidthLimits: {
2679
+ audio: StaticConfig.meetings.bandwidth.audio,
2680
+ video: StaticConfig.meetings.bandwidth.video,
2681
+ },
2682
+ startBitrate: StaticConfig.meetings.bandwidth.startBitrate,
2683
+ periodicKeyframes: 20,
2684
+ disableExtmap: !meeting.config.enableExtmap,
2685
+ disableRtx: !meeting.config.enableRtx,
2686
+ },
2687
+ };
2621
2688
 
2622
- // setup stubs
2623
- fakeMicrophoneStream = {
2624
- on: sinon.stub(),
2625
- off: sinon.stub(),
2626
- getSettings: sinon.stub().returns({
2627
- deviceId: 'some device id'
2628
- }),
2629
- muted: false,
2630
- setUnmuteAllowed: sinon.stub(),
2631
- setMuted: sinon.stub(),
2632
- setServerMuted: sinon.stub(),
2633
- outputStream: {
2634
- getTracks: () => {
2635
- return [{
2636
- id: 'fake mic'
2637
- }];
2638
- }
2639
- }
2640
- }
2689
+ // setup stubs
2690
+ fakeMicrophoneStream = {
2691
+ on: sinon.stub(),
2692
+ off: sinon.stub(),
2693
+ getSettings: sinon.stub().returns({
2694
+ deviceId: 'some device id',
2695
+ }),
2696
+ muted: false,
2697
+ setUnmuteAllowed: sinon.stub(),
2698
+ setMuted: sinon.stub(),
2699
+ setServerMuted: sinon.stub(),
2700
+ outputStream: {
2701
+ getTracks: () => {
2702
+ return [
2703
+ {
2704
+ id: 'fake mic',
2705
+ },
2706
+ ];
2707
+ },
2708
+ },
2709
+ };
2641
2710
 
2642
- fakeRoapMediaConnection = {
2643
- id: 'roap media connection',
2644
- close: sinon.stub(),
2645
- getConnectionState: sinon.stub().returns(ConnectionState.Connected),
2646
- initiateOffer: sinon.stub().resolves({}),
2647
- update: sinon.stub().resolves({}),
2648
- on: sinon.stub(),
2649
- };
2711
+ fakeRoapMediaConnection = {
2712
+ id: 'roap media connection',
2713
+ close: sinon.stub(),
2714
+ getConnectionState: sinon.stub().returns(ConnectionState.Connected),
2715
+ initiateOffer: sinon.stub().resolves({}),
2716
+ update: sinon.stub().resolves({}),
2717
+ on: sinon.stub(),
2718
+ };
2650
2719
 
2651
- fakeMultistreamRoapMediaConnection = {
2652
- id: 'multistream roap media connection',
2653
- close: sinon.stub(),
2654
- getConnectionState: sinon.stub().returns(ConnectionState.Connected),
2655
- initiateOffer: sinon.stub().resolves({}),
2656
- on: sinon.stub(),
2657
- requestMedia: sinon.stub(),
2658
- createReceiveSlot: sinon.stub().resolves({on: sinon.stub()}),
2659
- createSendSlot: sinon.stub().returns({
2660
- publishStream: sinon.stub(),
2661
- unpublishStream: sinon.stub(),
2662
- }),
2663
- enableMultistreamAudio: sinon.stub(),
2664
- };
2720
+ fakeMultistreamRoapMediaConnection = {
2721
+ id: 'multistream roap media connection',
2722
+ close: sinon.stub(),
2723
+ getConnectionState: sinon.stub().returns(ConnectionState.Connected),
2724
+ initiateOffer: sinon.stub().resolves({}),
2725
+ on: sinon.stub(),
2726
+ requestMedia: sinon.stub(),
2727
+ createReceiveSlot: sinon.stub().resolves({on: sinon.stub()}),
2728
+ createSendSlot: sinon.stub().returns({
2729
+ publishStream: sinon.stub(),
2730
+ unpublishStream: sinon.stub(),
2731
+ }),
2732
+ enableMultistreamAudio: sinon.stub(),
2733
+ };
2665
2734
 
2666
- roapMediaConnectionConstructorStub = sinon
2667
- .stub(internalMediaModule, 'RoapMediaConnection')
2668
- .returns(fakeRoapMediaConnection);
2735
+ roapMediaConnectionConstructorStub = sinon
2736
+ .stub(internalMediaModule, 'RoapMediaConnection')
2737
+ .returns(fakeRoapMediaConnection);
2669
2738
 
2670
- multistreamRoapMediaConnectionConstructorStub = sinon
2671
- .stub(internalMediaModule, 'MultistreamRoapMediaConnection')
2672
- .returns(fakeMultistreamRoapMediaConnection);
2739
+ multistreamRoapMediaConnectionConstructorStub = sinon
2740
+ .stub(internalMediaModule, 'MultistreamRoapMediaConnection')
2741
+ .returns(fakeMultistreamRoapMediaConnection);
2673
2742
 
2674
- locusMediaRequestStub = sinon.stub(WebexPlugin.prototype, 'request').resolves({body: {locus: { fullState: {}}}});
2675
- });
2743
+ locusMediaRequestStub = sinon
2744
+ .stub(WebexPlugin.prototype, 'request')
2745
+ .resolves({body: {locus: {fullState: {}}}});
2746
+ });
2676
2747
 
2677
- afterEach(() => {
2678
- clock.restore();
2679
- sinon.restore();
2680
- });
2748
+ afterEach(() => {
2749
+ clock.restore();
2750
+ sinon.restore();
2751
+ });
2681
2752
 
2682
- // helper function that waits until all promises are resolved and any queued up /media requests to Locus are sent out
2683
- const stableState = async () => {
2684
- await testUtils.flushPromises();
2685
- clock.tick(1); // needed because LocusMediaRequest uses Lodash.defer()
2686
- }
2753
+ // helper function that waits until all promises are resolved and any queued up /media requests to Locus are sent out
2754
+ const stableState = async () => {
2755
+ await testUtils.flushPromises();
2756
+ clock.tick(1); // needed because LocusMediaRequest uses Lodash.defer()
2757
+ };
2687
2758
 
2688
- const resetHistory = () => {
2689
- locusMediaRequestStub.resetHistory();
2690
- fakeRoapMediaConnection.update.resetHistory();
2691
- try{
2692
- meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream.resetHistory();
2693
- }
2694
- catch(e){}
2695
- };
2759
+ const resetHistory = () => {
2760
+ locusMediaRequestStub.resetHistory();
2761
+ fakeRoapMediaConnection.update.resetHistory();
2762
+ try {
2763
+ meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream.resetHistory();
2764
+ } catch (e) {}
2765
+ };
2696
2766
 
2697
- const getRoapListener = () => {
2698
- const roapMediaConnectionToCheck = isMultistream ? fakeMultistreamRoapMediaConnection : fakeRoapMediaConnection;
2767
+ const getRoapListener = () => {
2768
+ const roapMediaConnectionToCheck = isMultistream
2769
+ ? fakeMultistreamRoapMediaConnection
2770
+ : fakeRoapMediaConnection;
2699
2771
 
2700
- for(let idx = 0; idx < roapMediaConnectionToCheck.on.callCount; idx+= 1) {
2701
- if (roapMediaConnectionToCheck.on.getCall(idx).args[0] === Event.ROAP_MESSAGE_TO_SEND) {
2702
- return roapMediaConnectionToCheck.on.getCall(idx).args[1];
2772
+ for (let idx = 0; idx < roapMediaConnectionToCheck.on.callCount; idx += 1) {
2773
+ if (
2774
+ roapMediaConnectionToCheck.on.getCall(idx).args[0] === Event.ROAP_MESSAGE_TO_SEND
2775
+ ) {
2776
+ return roapMediaConnectionToCheck.on.getCall(idx).args[1];
2777
+ }
2703
2778
  }
2779
+ assert.fail(
2780
+ 'listener for "roap:messageToSend" (Event.ROAP_MESSAGE_TO_SEND) was not registered'
2781
+ );
2704
2782
  };
2705
- assert.fail(
2706
- 'listener for "roap:messageToSend" (Event.ROAP_MESSAGE_TO_SEND) was not registered'
2707
- );
2708
- };
2709
2783
 
2710
- // simulates a Roap offer being generated by the RoapMediaConnection
2711
- const simulateRoapOffer = async () => {
2712
- meeting.deferSDPAnswer = {resolve: sinon.stub()};
2713
- const roapListener = getRoapListener();
2714
-
2715
- await roapListener({roapMessage: roapOfferMessage});
2716
- await stableState();
2717
- };
2784
+ // simulates a Roap offer being generated by the RoapMediaConnection
2785
+ const simulateRoapOffer = async () => {
2786
+ meeting.deferSDPAnswer = {resolve: sinon.stub()};
2787
+ const roapListener = getRoapListener();
2718
2788
 
2719
- // simulates a Roap OK being sent
2720
- const simulateRoapOk = async () => {
2721
- const roapListener = getRoapListener();
2789
+ await roapListener({roapMessage: roapOfferMessage});
2790
+ await stableState();
2791
+ };
2722
2792
 
2723
- await roapListener({roapMessage: roapOKMessage});
2724
- await stableState();
2725
- };
2793
+ // simulates a Roap OK being sent
2794
+ const simulateRoapOk = async () => {
2795
+ const roapListener = getRoapListener();
2726
2796
 
2727
- const checkSdpOfferSent = ({audioMuted, videoMuted}) => {
2728
- const {sdp, seq, tieBreaker} = roapOfferMessage;
2797
+ await roapListener({roapMessage: roapOKMessage});
2798
+ await stableState();
2799
+ };
2729
2800
 
2730
- assert.calledWith(locusMediaRequestStub, {
2731
- method: 'PUT',
2732
- uri: `${meeting.selfUrl}/media`,
2733
- body: {
2734
- device: {
2735
- url: meeting.deviceUrl,
2736
- deviceType: meeting.config.deviceType,
2737
- regionCode: 'EU',
2738
- countryCode: 'UK',
2739
- },
2740
- correlationId: meeting.correlationId,
2741
- localMedias: [
2742
- {
2743
- localSdp: `{"audioMuted":${audioMuted},"videoMuted":${videoMuted},"roapMessage":{"messageType":"OFFER","sdps":["${sdp}"],"version":"2","seq":"${seq}","tieBreaker":"${tieBreaker}","headers":["includeAnswerInHttpResponse","noOkInTransaction"]}}`,
2744
- mediaId: 'fake media id',
2801
+ const checkSdpOfferSent = ({audioMuted, videoMuted}) => {
2802
+ const {sdp, seq, tieBreaker} = roapOfferMessage;
2803
+
2804
+ assert.calledWith(locusMediaRequestStub, {
2805
+ method: 'PUT',
2806
+ uri: `${meeting.selfUrl}/media`,
2807
+ body: {
2808
+ device: {
2809
+ url: meeting.deviceUrl,
2810
+ deviceType: meeting.config.deviceType,
2811
+ regionCode: 'EU',
2812
+ countryCode: 'UK',
2813
+ },
2814
+ correlationId: meeting.correlationId,
2815
+ localMedias: [
2816
+ {
2817
+ localSdp: `{"audioMuted":${audioMuted},"videoMuted":${videoMuted},"roapMessage":{"messageType":"OFFER","sdps":["${sdp}"],"version":"2","seq":"${seq}","tieBreaker":"${tieBreaker}","headers":["includeAnswerInHttpResponse","noOkInTransaction"]}}`,
2818
+ mediaId: 'fake media id',
2819
+ },
2820
+ ],
2821
+ clientMediaPreferences: {
2822
+ preferTranscoding: !meeting.isMultistream,
2823
+ joinCookie: undefined,
2824
+ ipver: 0,
2745
2825
  },
2746
- ],
2747
- clientMediaPreferences: {
2748
- preferTranscoding: !meeting.isMultistream,
2749
- joinCookie: undefined,
2750
- ipver: 0,
2751
2826
  },
2752
- },
2753
- });
2754
- };
2755
-
2756
- const checkOkSent = ({audioMuted, videoMuted}) => {
2757
- const {seq} = roapOKMessage;
2827
+ });
2828
+ };
2758
2829
 
2759
- assert.calledWith(locusMediaRequestStub, {
2760
- method: 'PUT',
2761
- uri: `${meeting.selfUrl}/media`,
2762
- body: {
2763
- device: {
2764
- url: meeting.deviceUrl,
2765
- deviceType: meeting.config.deviceType,
2766
- countryCode: 'UK',
2767
- regionCode: 'EU'
2768
- },
2769
- correlationId: meeting.correlationId,
2770
- clientMediaPreferences: {
2771
- preferTranscoding: !meeting.isMultistream,
2772
- ipver: undefined,
2773
- joinCookie: undefined
2774
- },
2775
- localMedias: [
2776
- {
2777
- localSdp: `{"audioMuted":${audioMuted},"videoMuted":${videoMuted},"roapMessage":{"messageType":"OK","version":"2","seq":"${seq}"}}`,
2778
- mediaId: 'fake media id'
2830
+ const checkOkSent = ({audioMuted, videoMuted}) => {
2831
+ const {seq} = roapOKMessage;
2832
+
2833
+ assert.calledWith(locusMediaRequestStub, {
2834
+ method: 'PUT',
2835
+ uri: `${meeting.selfUrl}/media`,
2836
+ body: {
2837
+ device: {
2838
+ url: meeting.deviceUrl,
2839
+ deviceType: meeting.config.deviceType,
2840
+ countryCode: 'UK',
2841
+ regionCode: 'EU',
2779
2842
  },
2780
- ],
2781
- },
2782
- });
2783
- };
2843
+ correlationId: meeting.correlationId,
2844
+ clientMediaPreferences: {
2845
+ preferTranscoding: !meeting.isMultistream,
2846
+ ipver: undefined,
2847
+ joinCookie: undefined,
2848
+ },
2849
+ localMedias: [
2850
+ {
2851
+ localSdp: `{"audioMuted":${audioMuted},"videoMuted":${videoMuted},"roapMessage":{"messageType":"OK","version":"2","seq":"${seq}"}}`,
2852
+ mediaId: 'fake media id',
2853
+ },
2854
+ ],
2855
+ },
2856
+ });
2857
+ };
2784
2858
 
2785
- const checkLocalMuteSentToLocus = ({audioMuted, videoMuted}) => {
2786
- assert.calledWith(locusMediaRequestStub, {
2787
- method: 'PUT',
2788
- uri: `${meeting.selfUrl}/media`,
2789
- body: {
2790
- device: {
2791
- url: meeting.deviceUrl,
2792
- deviceType: meeting.config.deviceType,
2793
- regionCode: 'EU',
2794
- countryCode: 'UK',
2859
+ const checkLocalMuteSentToLocus = ({audioMuted, videoMuted}) => {
2860
+ assert.calledWith(locusMediaRequestStub, {
2861
+ method: 'PUT',
2862
+ uri: `${meeting.selfUrl}/media`,
2863
+ body: {
2864
+ device: {
2865
+ url: meeting.deviceUrl,
2866
+ deviceType: meeting.config.deviceType,
2867
+ regionCode: 'EU',
2868
+ countryCode: 'UK',
2869
+ },
2870
+ correlationId: meeting.correlationId,
2871
+ localMedias: [
2872
+ {
2873
+ localSdp: `{"audioMuted":${audioMuted},"videoMuted":${videoMuted}}`,
2874
+ mediaId: 'fake media id',
2875
+ },
2876
+ ],
2877
+ clientMediaPreferences: {
2878
+ preferTranscoding: !meeting.isMultistream,
2879
+ ipver: undefined,
2880
+ },
2881
+ respOnlySdp: true,
2882
+ usingResource: null,
2795
2883
  },
2796
- correlationId: meeting.correlationId,
2797
- localMedias: [
2884
+ });
2885
+ };
2886
+
2887
+ const checkMediaConnectionCreated = ({
2888
+ mediaConnectionConfig,
2889
+ localStreams,
2890
+ direction,
2891
+ remoteQualityLevel,
2892
+ expectedDebugId,
2893
+ meetingId,
2894
+ }) => {
2895
+ if (isMultistream) {
2896
+ const {iceServers} = mediaConnectionConfig;
2897
+
2898
+ assert.calledOnceWithMatch(
2899
+ multistreamRoapMediaConnectionConstructorStub,
2798
2900
  {
2799
- localSdp: `{"audioMuted":${audioMuted},"videoMuted":${videoMuted}}`,
2800
- mediaId: 'fake media id',
2901
+ iceServers,
2801
2902
  },
2802
- ],
2803
- clientMediaPreferences: {
2804
- preferTranscoding: !meeting.isMultistream,
2805
- ipver: undefined
2806
- },
2807
- respOnlySdp: true,
2808
- usingResource: null,
2809
- },
2810
- });
2811
- };
2903
+ meetingId
2904
+ );
2812
2905
 
2813
- const checkMediaConnectionCreated = ({mediaConnectionConfig, localStreams, direction, remoteQualityLevel, expectedDebugId, meetingId}) => {
2814
- if (isMultistream) {
2815
- const {iceServers} = mediaConnectionConfig;
2816
-
2817
- assert.calledOnceWithMatch(multistreamRoapMediaConnectionConstructorStub, {
2818
- iceServers,
2819
- }, meetingId);
2820
-
2821
- assert.calledWith(fakeMultistreamRoapMediaConnection.createSendSlot, MediaType.AudioMain, direction.audio !== 'inactive');
2822
- assert.calledWith(fakeMultistreamRoapMediaConnection.createSendSlot, MediaType.VideoMain, direction.video !== 'inactive');
2823
- assert.calledWith(fakeMultistreamRoapMediaConnection.createSendSlot, MediaType.AudioSlides, direction.screenShare !== 'inactive');
2824
- assert.calledWith(fakeMultistreamRoapMediaConnection.createSendSlot, MediaType.VideoSlides, direction.screenShare !== 'inactive');
2825
-
2826
- for(let type in localStreams){
2827
- const stream = localStreams[type];
2828
- if(stream !== undefined){
2829
- switch(type){
2830
- case 'audio':
2831
- assert.calledOnceWithExactly(meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream, stream);
2832
- break;
2833
- case 'video':
2834
- assert.calledOnceWithExactly(meeting.sendSlotManager.getSlot(MediaType.VideoMain).publishStream, stream);
2835
- break;
2836
- case 'screenShareAudio':
2837
- assert.calledOnceWithExactly(meeting.sendSlotManager.getSlot(MediaType.AudioSlides).publishStream, stream);
2838
- break;
2839
- case 'screenShareVideo':
2840
- assert.calledOnceWithExactly(meeting.sendSlotManager.getSlot(MediaType.VideoSlides).publishStream, stream);
2841
- break;
2906
+ assert.calledWith(
2907
+ fakeMultistreamRoapMediaConnection.createSendSlot,
2908
+ MediaType.AudioMain,
2909
+ direction.audio !== 'inactive'
2910
+ );
2911
+ assert.calledWith(
2912
+ fakeMultistreamRoapMediaConnection.createSendSlot,
2913
+ MediaType.VideoMain,
2914
+ direction.video !== 'inactive'
2915
+ );
2916
+ assert.calledWith(
2917
+ fakeMultistreamRoapMediaConnection.createSendSlot,
2918
+ MediaType.AudioSlides,
2919
+ direction.screenShare !== 'inactive'
2920
+ );
2921
+ assert.calledWith(
2922
+ fakeMultistreamRoapMediaConnection.createSendSlot,
2923
+ MediaType.VideoSlides,
2924
+ direction.screenShare !== 'inactive'
2925
+ );
2926
+
2927
+ for (let type in localStreams) {
2928
+ const stream = localStreams[type];
2929
+ if (stream !== undefined) {
2930
+ switch (type) {
2931
+ case 'audio':
2932
+ assert.calledOnceWithExactly(
2933
+ meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream,
2934
+ stream
2935
+ );
2936
+ break;
2937
+ case 'video':
2938
+ assert.calledOnceWithExactly(
2939
+ meeting.sendSlotManager.getSlot(MediaType.VideoMain).publishStream,
2940
+ stream
2941
+ );
2942
+ break;
2943
+ case 'screenShareAudio':
2944
+ assert.calledOnceWithExactly(
2945
+ meeting.sendSlotManager.getSlot(MediaType.AudioSlides).publishStream,
2946
+ stream
2947
+ );
2948
+ break;
2949
+ case 'screenShareVideo':
2950
+ assert.calledOnceWithExactly(
2951
+ meeting.sendSlotManager.getSlot(MediaType.VideoSlides).publishStream,
2952
+ stream
2953
+ );
2954
+ break;
2955
+ }
2842
2956
  }
2843
2957
  }
2844
- }
2845
- } else {
2846
- assert.calledOnceWithExactly(roapMediaConnectionConstructorStub, mediaConnectionConfig,
2847
- {
2848
- localTracks: {
2849
- audio: localStreams.audio?.outputStream?.getTracks()[0],
2850
- video: localStreams.video?.outputStream?.getTracks()[0],
2851
- screenShareVideo: localStreams.screenShareVideo?.outputStream?.getTracks()[0],
2852
- screenShareAudio: localStreams.screenShareAudio?.outputStream?.getTracks()[0],
2958
+ } else {
2959
+ assert.calledOnceWithExactly(
2960
+ roapMediaConnectionConstructorStub,
2961
+ mediaConnectionConfig,
2962
+ {
2963
+ localTracks: {
2964
+ audio: localStreams.audio?.outputStream?.getTracks()[0],
2965
+ video: localStreams.video?.outputStream?.getTracks()[0],
2966
+ screenShareVideo: localStreams.screenShareVideo?.outputStream?.getTracks()[0],
2967
+ screenShareAudio: localStreams.screenShareAudio?.outputStream?.getTracks()[0],
2968
+ },
2969
+ direction: {
2970
+ audio: direction.audio,
2971
+ video: direction.video,
2972
+ screenShareVideo: direction.screenShare,
2973
+ },
2974
+ remoteQualityLevel,
2853
2975
  },
2854
- direction: {audio: direction.audio, video: direction.video, screenShareVideo: direction.screenShare},
2855
- remoteQualityLevel,
2976
+ expectedDebugId
2977
+ );
2978
+ }
2979
+ };
2980
+
2981
+ it('addMedia() works correctly when media is enabled without tracks to publish', async () => {
2982
+ await meeting.addMedia();
2983
+ await simulateRoapOffer();
2984
+ await simulateRoapOk();
2985
+
2986
+ // check RoapMediaConnection was created correctly
2987
+ checkMediaConnectionCreated({
2988
+ mediaConnectionConfig: expectedMediaConnectionConfig,
2989
+ localStreams: {
2990
+ audio: undefined,
2991
+ video: undefined,
2992
+ screenShareVideo: undefined,
2993
+ screenShareAudio: undefined,
2856
2994
  },
2857
- expectedDebugId
2858
- );
2859
- }
2860
- };
2995
+ direction: {
2996
+ audio: 'sendrecv',
2997
+ video: 'sendrecv',
2998
+ screenShare: 'recvonly',
2999
+ },
3000
+ remoteQualityLevel: 'HIGH',
3001
+ expectedDebugId,
3002
+ meetingId: meeting.id,
3003
+ });
2861
3004
 
2862
- it('addMedia() works correctly when media is enabled without tracks to publish', async () => {
2863
- await meeting.addMedia();
2864
- await simulateRoapOffer();
2865
- await simulateRoapOk();
2866
-
2867
- // check RoapMediaConnection was created correctly
2868
- checkMediaConnectionCreated({
2869
- mediaConnectionConfig: expectedMediaConnectionConfig,
2870
- localStreams: {
2871
- audio: undefined,
2872
- video: undefined,
2873
- screenShareVideo: undefined,
2874
- screenShareAudio: undefined,
2875
- },
2876
- direction: {
2877
- audio: 'sendrecv',
2878
- video: 'sendrecv',
2879
- screenShare: 'recvonly',
2880
- },
2881
- remoteQualityLevel: 'HIGH',
2882
- expectedDebugId,
2883
- meetingId: meeting.id
3005
+ // and SDP offer was sent with the right audioMuted/videoMuted values
3006
+ checkSdpOfferSent({audioMuted: true, videoMuted: true});
3007
+ // check OK was sent with the right audioMuted/videoMuted values
3008
+ checkOkSent({audioMuted: true, videoMuted: true});
3009
+
3010
+ // and that these were the only /media requests that were sent
3011
+ assert.calledTwice(locusMediaRequestStub);
2884
3012
  });
2885
3013
 
2886
- // and SDP offer was sent with the right audioMuted/videoMuted values
2887
- checkSdpOfferSent({audioMuted: true, videoMuted: true});
2888
- // check OK was sent with the right audioMuted/videoMuted values
2889
- checkOkSent({audioMuted: true, videoMuted: true});
3014
+ it('addMedia() works correctly when media is enabled with streams to publish', async () => {
3015
+ await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}});
3016
+ await simulateRoapOffer();
3017
+ await simulateRoapOk();
2890
3018
 
2891
- // and that these were the only /media requests that were sent
2892
- assert.calledTwice(locusMediaRequestStub);
2893
- });
3019
+ // check RoapMediaConnection was created correctly
3020
+ checkMediaConnectionCreated({
3021
+ mediaConnectionConfig: expectedMediaConnectionConfig,
3022
+ localStreams: {
3023
+ audio: fakeMicrophoneStream,
3024
+ video: undefined,
3025
+ screenShareVideo: undefined,
3026
+ screenShareAudio: undefined,
3027
+ },
3028
+ direction: {
3029
+ audio: 'sendrecv',
3030
+ video: 'sendrecv',
3031
+ screenShare: 'recvonly',
3032
+ },
3033
+ remoteQualityLevel: 'HIGH',
3034
+ expectedDebugId,
3035
+ meetingId: meeting.id,
3036
+ });
2894
3037
 
2895
- it('addMedia() works correctly when media is enabled with streams to publish', async () => {
2896
- await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}});
2897
- await simulateRoapOffer();
2898
- await simulateRoapOk();
3038
+ // and SDP offer was sent with the right audioMuted/videoMuted values
3039
+ checkSdpOfferSent({audioMuted: false, videoMuted: true});
3040
+ // check OK was sent with the right audioMuted/videoMuted values
3041
+ checkOkSent({audioMuted: false, videoMuted: true});
2899
3042
 
2900
- // check RoapMediaConnection was created correctly
2901
- checkMediaConnectionCreated({
2902
- mediaConnectionConfig: expectedMediaConnectionConfig,
2903
- localStreams: {
2904
- audio: fakeMicrophoneStream,
2905
- video: undefined,
2906
- screenShareVideo: undefined,
2907
- screenShareAudio: undefined,
2908
- },
2909
- direction: {
2910
- audio: 'sendrecv',
2911
- video: 'sendrecv',
2912
- screenShare: 'recvonly',
2913
- },
2914
- remoteQualityLevel: 'HIGH',
2915
- expectedDebugId,
2916
- meetingId: meeting.id
3043
+ // and that these were the only /media requests that were sent
3044
+ assert.calledTwice(locusMediaRequestStub);
2917
3045
  });
2918
3046
 
2919
- // and SDP offer was sent with the right audioMuted/videoMuted values
2920
- checkSdpOfferSent({audioMuted: false, videoMuted: true});
2921
- // check OK was sent with the right audioMuted/videoMuted values
2922
- checkOkSent({audioMuted: false, videoMuted: true});
2923
-
2924
- // and that these were the only /media requests that were sent
2925
- assert.calledTwice(locusMediaRequestStub);
2926
- });
3047
+ it('addMedia() works correctly when media is enabled with tracks to publish and track is muted', async () => {
3048
+ fakeMicrophoneStream.muted = true;
2927
3049
 
2928
- it('addMedia() works correctly when media is enabled with tracks to publish and track is muted', async () => {
2929
- fakeMicrophoneStream.muted = true;
3050
+ await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}});
3051
+ await simulateRoapOffer();
3052
+ await simulateRoapOk();
2930
3053
 
2931
- await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}});
2932
- await simulateRoapOffer();
2933
- await simulateRoapOk();
3054
+ // check RoapMediaConnection was created correctly
3055
+ checkMediaConnectionCreated({
3056
+ mediaConnectionConfig: expectedMediaConnectionConfig,
3057
+ localStreams: {
3058
+ audio: fakeMicrophoneStream,
3059
+ video: undefined,
3060
+ screenShareVideo: undefined,
3061
+ screenShareAudio: undefined,
3062
+ },
3063
+ direction: {
3064
+ audio: 'sendrecv',
3065
+ video: 'sendrecv',
3066
+ screenShare: 'recvonly',
3067
+ },
3068
+ remoteQualityLevel: 'HIGH',
3069
+ expectedDebugId,
3070
+ meetingId: meeting.id,
3071
+ });
3072
+ // and SDP offer was sent with the right audioMuted/videoMuted values
3073
+ checkSdpOfferSent({audioMuted: true, videoMuted: true});
3074
+ // check OK was sent with the right audioMuted/videoMuted values
3075
+ checkOkSent({audioMuted: true, videoMuted: true});
2934
3076
 
2935
- // check RoapMediaConnection was created correctly
2936
- checkMediaConnectionCreated({
2937
- mediaConnectionConfig: expectedMediaConnectionConfig,
2938
- localStreams: {
2939
- audio: fakeMicrophoneStream,
2940
- video: undefined,
2941
- screenShareVideo: undefined,
2942
- screenShareAudio: undefined,
2943
- },
2944
- direction: {
2945
- audio: 'sendrecv',
2946
- video: 'sendrecv',
2947
- screenShare: 'recvonly',
2948
- },
2949
- remoteQualityLevel: 'HIGH',
2950
- expectedDebugId,
2951
- meetingId: meeting.id
3077
+ // and that these were the only /media requests that were sent
3078
+ assert.calledTwice(locusMediaRequestStub);
2952
3079
  });
2953
- // and SDP offer was sent with the right audioMuted/videoMuted values
2954
- checkSdpOfferSent({audioMuted: true, videoMuted: true});
2955
- // check OK was sent with the right audioMuted/videoMuted values
2956
- checkOkSent({audioMuted: true, videoMuted: true});
2957
3080
 
2958
- // and that these were the only /media requests that were sent
2959
- assert.calledTwice(locusMediaRequestStub);
2960
- });
3081
+ it('addMedia() works correctly when media is disabled with tracks to publish', async () => {
3082
+ await meeting.addMedia({
3083
+ localStreams: {microphone: fakeMicrophoneStream},
3084
+ audioEnabled: false,
3085
+ });
3086
+ await simulateRoapOffer();
3087
+ await simulateRoapOk();
2961
3088
 
2962
- it('addMedia() works correctly when media is disabled with tracks to publish', async () => {
2963
- await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}, audioEnabled: false});
2964
- await simulateRoapOffer();
2965
- await simulateRoapOk();
3089
+ // check RoapMediaConnection was created correctly
3090
+ checkMediaConnectionCreated({
3091
+ mediaConnectionConfig: expectedMediaConnectionConfig,
3092
+ localStreams: {
3093
+ audio: fakeMicrophoneStream,
3094
+ video: undefined,
3095
+ screenShareVideo: undefined,
3096
+ screenShareAudio: undefined,
3097
+ },
3098
+ direction: {
3099
+ audio: 'inactive',
3100
+ video: 'sendrecv',
3101
+ screenShare: 'recvonly',
3102
+ },
3103
+ remoteQualityLevel: 'HIGH',
3104
+ expectedDebugId,
3105
+ meetingId: meeting.id,
3106
+ });
2966
3107
 
2967
- // check RoapMediaConnection was created correctly
2968
- checkMediaConnectionCreated({
2969
- mediaConnectionConfig: expectedMediaConnectionConfig,
2970
- localStreams: {
2971
- audio: fakeMicrophoneStream,
2972
- video: undefined,
2973
- screenShareVideo: undefined,
2974
- screenShareAudio: undefined,
2975
- },
2976
- direction: {
2977
- audio: 'inactive',
2978
- video: 'sendrecv',
2979
- screenShare: 'recvonly',
2980
- },
2981
- remoteQualityLevel: 'HIGH',
2982
- expectedDebugId,
2983
- meetingId: meeting.id
3108
+ // and SDP offer was sent with the right audioMuted/videoMuted values
3109
+ checkSdpOfferSent({audioMuted: true, videoMuted: true});
3110
+ // check OK was sent with the right audioMuted/videoMuted values
3111
+ checkOkSent({audioMuted: true, videoMuted: true});
3112
+
3113
+ // and that these were the only /media requests that were sent
3114
+ assert.calledTwice(locusMediaRequestStub);
2984
3115
  });
2985
3116
 
2986
- // and SDP offer was sent with the right audioMuted/videoMuted values
2987
- checkSdpOfferSent({audioMuted: true, videoMuted: true});
2988
- // check OK was sent with the right audioMuted/videoMuted values
2989
- checkOkSent({audioMuted: true, videoMuted: true});
3117
+ it('addMedia() works correctly when media is disabled with no tracks to publish', async () => {
3118
+ await meeting.addMedia({audioEnabled: false});
3119
+ await simulateRoapOffer();
3120
+ await simulateRoapOk();
2990
3121
 
2991
- // and that these were the only /media requests that were sent
2992
- assert.calledTwice(locusMediaRequestStub);
2993
- });
3122
+ // check RoapMediaConnection was created correctly
3123
+ checkMediaConnectionCreated({
3124
+ mediaConnectionConfig: expectedMediaConnectionConfig,
3125
+ localStreams: {
3126
+ audio: undefined,
3127
+ video: undefined,
3128
+ screenShareVideo: undefined,
3129
+ screenShareAudio: undefined,
3130
+ },
3131
+ direction: {
3132
+ audio: 'inactive',
3133
+ video: 'sendrecv',
3134
+ screenShare: 'recvonly',
3135
+ },
3136
+ remoteQualityLevel: 'HIGH',
3137
+ expectedDebugId,
3138
+ meetingId: meeting.id,
3139
+ });
2994
3140
 
2995
- it('addMedia() works correctly when media is disabled with no tracks to publish', async () => {
2996
- await meeting.addMedia({audioEnabled: false});
2997
- await simulateRoapOffer();
2998
- await simulateRoapOk();
3141
+ // and SDP offer was sent with the right audioMuted/videoMuted values
3142
+ checkSdpOfferSent({audioMuted: true, videoMuted: true});
3143
+ // check OK was sent with the right audioMuted/videoMuted values
3144
+ checkOkSent({audioMuted: true, videoMuted: true});
2999
3145
 
3000
- // check RoapMediaConnection was created correctly
3001
- checkMediaConnectionCreated({
3002
- mediaConnectionConfig: expectedMediaConnectionConfig,
3003
- localStreams: {
3004
- audio: undefined,
3005
- video: undefined,
3006
- screenShareVideo: undefined,
3007
- screenShareAudio: undefined,
3008
- },
3009
- direction: {
3010
- audio: 'inactive',
3011
- video: 'sendrecv',
3012
- screenShare: 'recvonly',
3013
- },
3014
- remoteQualityLevel: 'HIGH',
3015
- expectedDebugId,
3016
- meetingId: meeting.id
3146
+ // and that these were the only /media requests that were sent
3147
+ assert.calledTwice(locusMediaRequestStub);
3017
3148
  });
3018
3149
 
3019
- // and SDP offer was sent with the right audioMuted/videoMuted values
3020
- checkSdpOfferSent({audioMuted: true, videoMuted: true});
3021
- // check OK was sent with the right audioMuted/videoMuted values
3022
- checkOkSent({audioMuted: true, videoMuted: true});
3023
-
3024
- // and that these were the only /media requests that were sent
3025
- assert.calledTwice(locusMediaRequestStub);
3026
- });
3150
+ it('addMedia() works correctly when video is disabled with no tracks to publish', async () => {
3151
+ await meeting.addMedia({videoEnabled: false});
3152
+ await simulateRoapOffer();
3153
+ await simulateRoapOk();
3027
3154
 
3155
+ // check RoapMediaConnection was created correctly
3156
+ checkMediaConnectionCreated({
3157
+ mediaConnectionConfig: expectedMediaConnectionConfig,
3158
+ localStreams: {
3159
+ audio: undefined,
3160
+ video: undefined,
3161
+ screenShareVideo: undefined,
3162
+ screenShareAudio: undefined,
3163
+ },
3164
+ direction: {
3165
+ audio: 'sendrecv',
3166
+ video: 'inactive',
3167
+ screenShare: 'recvonly',
3168
+ },
3169
+ remoteQualityLevel: 'HIGH',
3170
+ expectedDebugId,
3171
+ meetingId: meeting.id,
3172
+ });
3028
3173
 
3029
- it('addMedia() works correctly when video is disabled with no tracks to publish', async () => {
3030
- await meeting.addMedia({videoEnabled: false});
3031
- await simulateRoapOffer();
3032
- await simulateRoapOk();
3174
+ // and SDP offer was sent with the right audioMuted/videoMuted values
3175
+ checkSdpOfferSent({audioMuted: true, videoMuted: true});
3176
+ // check OK was sent with the right audioMuted/videoMuted values
3177
+ checkOkSent({audioMuted: true, videoMuted: true});
3033
3178
 
3034
- // check RoapMediaConnection was created correctly
3035
- checkMediaConnectionCreated({
3036
- mediaConnectionConfig: expectedMediaConnectionConfig,
3037
- localStreams: {
3038
- audio: undefined,
3039
- video: undefined,
3040
- screenShareVideo: undefined,
3041
- screenShareAudio: undefined,
3042
- },
3043
- direction: {
3044
- audio: 'sendrecv',
3045
- video: 'inactive',
3046
- screenShare: 'recvonly',
3047
- },
3048
- remoteQualityLevel: 'HIGH',
3049
- expectedDebugId,
3050
- meetingId: meeting.id
3179
+ // and that these were the only /media requests that were sent
3180
+ assert.calledTwice(locusMediaRequestStub);
3051
3181
  });
3052
3182
 
3053
- // and SDP offer was sent with the right audioMuted/videoMuted values
3054
- checkSdpOfferSent({audioMuted: true, videoMuted: true});
3055
- // check OK was sent with the right audioMuted/videoMuted values
3056
- checkOkSent({audioMuted: true, videoMuted: true});
3057
-
3058
- // and that these were the only /media requests that were sent
3059
- assert.calledTwice(locusMediaRequestStub);
3060
- });
3183
+ it('addMedia() works correctly when screen share is disabled with no tracks to publish', async () => {
3184
+ await meeting.addMedia({shareAudioEnabled: false, shareVideoEnabled: false});
3185
+ await simulateRoapOffer();
3186
+ await simulateRoapOk();
3061
3187
 
3062
- it('addMedia() works correctly when screen share is disabled with no tracks to publish', async () => {
3063
- await meeting.addMedia({shareAudioEnabled: false, shareVideoEnabled: false});
3064
- await simulateRoapOffer();
3065
- await simulateRoapOk();
3188
+ // check RoapMediaConnection was created correctly
3189
+ checkMediaConnectionCreated({
3190
+ mediaConnectionConfig: expectedMediaConnectionConfig,
3191
+ localStreams: {
3192
+ audio: undefined,
3193
+ video: undefined,
3194
+ screenShareVideo: undefined,
3195
+ screenShareAudio: undefined,
3196
+ },
3197
+ direction: {
3198
+ audio: 'sendrecv',
3199
+ video: 'sendrecv',
3200
+ screenShare: 'inactive',
3201
+ },
3202
+ remoteQualityLevel: 'HIGH',
3203
+ expectedDebugId,
3204
+ meetingId: meeting.id,
3205
+ });
3066
3206
 
3207
+ // and SDP offer was sent with the right audioMuted/videoMuted values
3208
+ checkSdpOfferSent({audioMuted: true, videoMuted: true});
3209
+ // check OK was sent with the right audioMuted/videoMuted values
3210
+ checkOkSent({audioMuted: true, videoMuted: true});
3067
3211
 
3068
- // check RoapMediaConnection was created correctly
3069
- checkMediaConnectionCreated({
3070
- mediaConnectionConfig: expectedMediaConnectionConfig,
3071
- localStreams: {
3072
- audio: undefined,
3073
- video: undefined,
3074
- screenShareVideo: undefined,
3075
- screenShareAudio: undefined,
3076
- },
3077
- direction: {
3078
- audio: 'sendrecv',
3079
- video: 'sendrecv',
3080
- screenShare: 'inactive',
3081
- },
3082
- remoteQualityLevel: 'HIGH',
3083
- expectedDebugId,
3084
- meetingId: meeting.id
3212
+ // and that these were the only /media requests that were sent
3213
+ assert.calledTwice(locusMediaRequestStub);
3085
3214
  });
3086
3215
 
3087
- // and SDP offer was sent with the right audioMuted/videoMuted values
3088
- checkSdpOfferSent({audioMuted: true, videoMuted: true});
3089
- // check OK was sent with the right audioMuted/videoMuted values
3090
- checkOkSent({audioMuted: true, videoMuted: true});
3091
-
3092
- // and that these were the only /media requests that were sent
3093
- assert.calledTwice(locusMediaRequestStub);
3094
- });
3095
-
3096
- describe('publishStreams()/unpublishStreams() calls', () => {
3097
- [
3098
- {mediaEnabled: true, expected: {direction: 'sendrecv', localMuteSentValue: false}},
3099
- {mediaEnabled: false, expected: {direction: 'inactive', localMuteSentValue: undefined}}
3100
- ]
3101
- .forEach(({mediaEnabled, expected}) => {
3102
- it(`first publishStreams() call while media is ${mediaEnabled ? 'enabled' : 'disabled'}`, async () => {
3216
+ describe('publishStreams()/unpublishStreams() calls', () => {
3217
+ [
3218
+ {mediaEnabled: true, expected: {direction: 'sendrecv', localMuteSentValue: false}},
3219
+ {
3220
+ mediaEnabled: false,
3221
+ expected: {direction: 'inactive', localMuteSentValue: undefined},
3222
+ },
3223
+ ].forEach(({mediaEnabled, expected}) => {
3224
+ it(`first publishStreams() call while media is ${
3225
+ mediaEnabled ? 'enabled' : 'disabled'
3226
+ }`, async () => {
3103
3227
  await meeting.addMedia({audioEnabled: mediaEnabled});
3104
3228
  await simulateRoapOffer();
3105
3229
  await simulateRoapOk();
@@ -3121,10 +3245,18 @@ describe('plugin-meetings', () => {
3121
3245
  }
3122
3246
 
3123
3247
  if (isMultistream) {
3124
- assert.calledOnceWithExactly(meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream, fakeMicrophoneStream);
3248
+ assert.calledOnceWithExactly(
3249
+ meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream,
3250
+ fakeMicrophoneStream
3251
+ );
3125
3252
  } else {
3126
3253
  assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
3127
- localTracks: { audio: fakeMicrophoneStream.outputStream.getTracks()[0], video: null, screenShareVideo: null, screenShareAudio: null },
3254
+ localTracks: {
3255
+ audio: fakeMicrophoneStream.outputStream.getTracks()[0],
3256
+ video: null,
3257
+ screenShareVideo: null,
3258
+ screenShareAudio: null,
3259
+ },
3128
3260
  direction: {
3129
3261
  audio: expected.direction,
3130
3262
  video: 'sendrecv',
@@ -3135,7 +3267,9 @@ describe('plugin-meetings', () => {
3135
3267
  }
3136
3268
  });
3137
3269
 
3138
- it(`second publishStreams() call while media is ${mediaEnabled ? 'enabled' : 'disabled'}`, async () => {
3270
+ it(`second publishStreams() call while media is ${
3271
+ mediaEnabled ? 'enabled' : 'disabled'
3272
+ }`, async () => {
3139
3273
  await meeting.addMedia({audioEnabled: mediaEnabled});
3140
3274
  await simulateRoapOffer();
3141
3275
  await simulateRoapOk();
@@ -3152,22 +3286,32 @@ describe('plugin-meetings', () => {
3152
3286
  setMuted: sinon.stub(),
3153
3287
  outputStream: {
3154
3288
  getTracks: () => {
3155
- return [{
3156
- id: 'fake mic 2',
3157
- }];
3158
- }
3159
- }
3160
- }
3289
+ return [
3290
+ {
3291
+ id: 'fake mic 2',
3292
+ },
3293
+ ];
3294
+ },
3295
+ },
3296
+ };
3161
3297
 
3162
3298
  await meeting.publishStreams({microphone: fakeMicrophoneStream2});
3163
3299
  await stableState();
3164
3300
 
3165
3301
  // only the roap media connection should be updated
3166
3302
  if (isMultistream) {
3167
- assert.calledOnceWithExactly(meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream, fakeMicrophoneStream2);
3303
+ assert.calledOnceWithExactly(
3304
+ meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream,
3305
+ fakeMicrophoneStream2
3306
+ );
3168
3307
  } else {
3169
3308
  assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
3170
- localTracks: { audio: fakeMicrophoneStream2.outputStream.getTracks()[0], video: null, screenShareVideo: null, screenShareAudio: null },
3309
+ localTracks: {
3310
+ audio: fakeMicrophoneStream2.outputStream.getTracks()[0],
3311
+ video: null,
3312
+ screenShareVideo: null,
3313
+ screenShareAudio: null,
3314
+ },
3171
3315
  direction: {
3172
3316
  audio: expected.direction,
3173
3317
  video: 'sendrecv',
@@ -3181,7 +3325,9 @@ describe('plugin-meetings', () => {
3181
3325
  assert.notCalled(locusMediaRequestStub);
3182
3326
  });
3183
3327
 
3184
- it(`unpublishStreams() call while media is ${mediaEnabled ? 'enabled' : 'disabled'}`, async () => {
3328
+ it(`unpublishStreams() call while media is ${
3329
+ mediaEnabled ? 'enabled' : 'disabled'
3330
+ }`, async () => {
3185
3331
  await meeting.addMedia({audioEnabled: mediaEnabled});
3186
3332
  await simulateRoapOffer();
3187
3333
  await simulateRoapOk();
@@ -3195,10 +3341,17 @@ describe('plugin-meetings', () => {
3195
3341
 
3196
3342
  // the roap media connection should be updated
3197
3343
  if (isMultistream) {
3198
- assert.calledOnce(meeting.sendSlotManager.getSlot(MediaType.AudioMain).unpublishStream);
3344
+ assert.calledOnce(
3345
+ meeting.sendSlotManager.getSlot(MediaType.AudioMain).unpublishStream
3346
+ );
3199
3347
  } else {
3200
3348
  assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
3201
- localTracks: { audio: null, video: null, screenShareVideo: null, screenShareAudio: null },
3349
+ localTracks: {
3350
+ audio: null,
3351
+ video: null,
3352
+ screenShareVideo: null,
3353
+ screenShareAudio: null,
3354
+ },
3202
3355
  direction: {
3203
3356
  audio: expected.direction,
3204
3357
  video: 'sendrecv',
@@ -3221,180 +3374,194 @@ describe('plugin-meetings', () => {
3221
3374
  }
3222
3375
  });
3223
3376
  });
3224
- });
3225
-
3226
- describe('updateMedia()', () => {
3377
+ });
3227
3378
 
3228
- const addMedia = async (enableMedia, stream) => {
3229
- await meeting.addMedia({audioEnabled: enableMedia, localStreams: {microphone: stream}});
3230
- await simulateRoapOffer();
3231
- await simulateRoapOk();
3379
+ describe('updateMedia()', () => {
3380
+ const addMedia = async (enableMedia, stream) => {
3381
+ await meeting.addMedia({
3382
+ audioEnabled: enableMedia,
3383
+ localStreams: {microphone: stream},
3384
+ });
3385
+ await simulateRoapOffer();
3386
+ await simulateRoapOk();
3232
3387
 
3233
- resetHistory();
3234
- }
3388
+ resetHistory();
3389
+ };
3235
3390
 
3236
- const checkAudioEnabled = (expectedStream, expectedDirection) => {
3237
- if (isMultistream) {
3238
- assert.equal(meeting.sendSlotManager.getSlot(MediaType.AudioMain).active, expectedDirection !== 'inactive');
3239
- } else {
3240
- assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
3241
- localTracks: { audio: expectedStream?.outputStream.getTracks()[0] ?? null, video: null, screenShareVideo: null, screenShareAudio: null },
3242
- direction: {
3243
- audio: expectedDirection,
3244
- video: 'sendrecv',
3245
- screenShareVideo: 'recvonly',
3246
- },
3247
- remoteQualityLevel: 'HIGH'
3248
- });
3249
- }
3250
- }
3391
+ const checkAudioEnabled = (expectedStream, expectedDirection) => {
3392
+ if (isMultistream) {
3393
+ assert.equal(
3394
+ meeting.sendSlotManager.getSlot(MediaType.AudioMain).active,
3395
+ expectedDirection !== 'inactive'
3396
+ );
3397
+ } else {
3398
+ assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
3399
+ localTracks: {
3400
+ audio: expectedStream?.outputStream.getTracks()[0] ?? null,
3401
+ video: null,
3402
+ screenShareVideo: null,
3403
+ screenShareAudio: null,
3404
+ },
3405
+ direction: {
3406
+ audio: expectedDirection,
3407
+ video: 'sendrecv',
3408
+ screenShareVideo: 'recvonly',
3409
+ },
3410
+ remoteQualityLevel: 'HIGH',
3411
+ });
3412
+ }
3413
+ };
3251
3414
 
3252
- it('updateMedia() disables media when nothing is published', async () => {
3253
- await addMedia(true);
3415
+ it('updateMedia() disables media when nothing is published', async () => {
3416
+ await addMedia(true);
3254
3417
 
3255
- await meeting.updateMedia({audioEnabled: false});
3418
+ await meeting.updateMedia({audioEnabled: false});
3256
3419
 
3257
- // the roap media connection should be updated
3258
- checkAudioEnabled(null, 'inactive');
3420
+ // the roap media connection should be updated
3421
+ checkAudioEnabled(null, 'inactive');
3259
3422
 
3260
- // and that would trigger a new offer so we simulate it happening
3261
- await simulateRoapOffer();
3423
+ // and that would trigger a new offer so we simulate it happening
3424
+ await simulateRoapOffer();
3262
3425
 
3263
- // check SDP offer was sent with the right audioMuted/videoMuted values
3264
- checkSdpOfferSent({audioMuted: true, videoMuted: true});
3426
+ // check SDP offer was sent with the right audioMuted/videoMuted values
3427
+ checkSdpOfferSent({audioMuted: true, videoMuted: true});
3265
3428
 
3266
- // simulate OK being sent in response to remote answer being received
3267
- await simulateRoapOk();
3429
+ // simulate OK being sent in response to remote answer being received
3430
+ await simulateRoapOk();
3268
3431
 
3269
- // check OK was sent with the right audioMuted/videoMuted values
3270
- checkOkSent({audioMuted: true, videoMuted: true});
3432
+ // check OK was sent with the right audioMuted/videoMuted values
3433
+ checkOkSent({audioMuted: true, videoMuted: true});
3271
3434
 
3272
- // and no other local mute requests were sent to Locus
3273
- assert.calledTwice(locusMediaRequestStub);
3274
- });
3435
+ // and no other local mute requests were sent to Locus
3436
+ assert.calledTwice(locusMediaRequestStub);
3437
+ });
3275
3438
 
3276
- it('updateMedia() enables media when nothing is published', async () => {
3277
- await addMedia(false);
3439
+ it('updateMedia() enables media when nothing is published', async () => {
3440
+ await addMedia(false);
3278
3441
 
3279
- await meeting.updateMedia({audioEnabled: true});
3442
+ await meeting.updateMedia({audioEnabled: true});
3280
3443
 
3281
- // the roap media connection should be updated
3282
- checkAudioEnabled(null, 'sendrecv');
3444
+ // the roap media connection should be updated
3445
+ checkAudioEnabled(null, 'sendrecv');
3283
3446
 
3284
- // and that would trigger a new offer so we simulate it happening
3285
- await simulateRoapOffer();
3447
+ // and that would trigger a new offer so we simulate it happening
3448
+ await simulateRoapOffer();
3286
3449
 
3287
- // check SDP offer was sent with the right audioMuted/videoMuted values
3288
- checkSdpOfferSent({audioMuted: true, videoMuted: true});
3450
+ // check SDP offer was sent with the right audioMuted/videoMuted values
3451
+ checkSdpOfferSent({audioMuted: true, videoMuted: true});
3289
3452
 
3290
- // simulate OK being sent in response to remote answer being received
3291
- await simulateRoapOk();
3453
+ // simulate OK being sent in response to remote answer being received
3454
+ await simulateRoapOk();
3292
3455
 
3293
- // check OK was sent with the right audioMuted/videoMuted values
3294
- checkOkSent({audioMuted: true, videoMuted: true});
3456
+ // check OK was sent with the right audioMuted/videoMuted values
3457
+ checkOkSent({audioMuted: true, videoMuted: true});
3295
3458
 
3296
- // and no other local mute requests were sent to Locus
3297
- assert.calledTwice(locusMediaRequestStub);
3298
- });
3459
+ // and no other local mute requests were sent to Locus
3460
+ assert.calledTwice(locusMediaRequestStub);
3461
+ });
3299
3462
 
3300
- it('updateMedia() disables media when stream is published', async () => {
3301
- await addMedia(true, fakeMicrophoneStream);
3463
+ it('updateMedia() disables media when stream is published', async () => {
3464
+ await addMedia(true, fakeMicrophoneStream);
3302
3465
 
3303
- await meeting.updateMedia({audioEnabled: false});
3304
- await stableState();
3466
+ await meeting.updateMedia({audioEnabled: false});
3467
+ await stableState();
3305
3468
 
3306
- // the roap media connection should be updated
3307
- checkAudioEnabled(fakeMicrophoneStream, 'inactive');
3469
+ // the roap media connection should be updated
3470
+ checkAudioEnabled(fakeMicrophoneStream, 'inactive');
3308
3471
 
3309
- checkLocalMuteSentToLocus({audioMuted: true, videoMuted: true});
3472
+ checkLocalMuteSentToLocus({audioMuted: true, videoMuted: true});
3310
3473
 
3311
- locusMediaRequestStub.resetHistory();
3474
+ locusMediaRequestStub.resetHistory();
3312
3475
 
3313
- // and that would trigger a new offer so we simulate it happening
3314
- await simulateRoapOffer();
3476
+ // and that would trigger a new offer so we simulate it happening
3477
+ await simulateRoapOffer();
3315
3478
 
3316
- // check SDP offer was sent with the right audioMuted/videoMuted values
3317
- checkSdpOfferSent({audioMuted: true, videoMuted: true});
3479
+ // check SDP offer was sent with the right audioMuted/videoMuted values
3480
+ checkSdpOfferSent({audioMuted: true, videoMuted: true});
3318
3481
 
3319
- // simulate OK being sent in response to remote answer being received
3320
- await simulateRoapOk();
3482
+ // simulate OK being sent in response to remote answer being received
3483
+ await simulateRoapOk();
3321
3484
 
3322
- // check OK was sent with the right audioMuted/videoMuted values
3323
- checkOkSent({audioMuted: true, videoMuted: true});
3485
+ // check OK was sent with the right audioMuted/videoMuted values
3486
+ checkOkSent({audioMuted: true, videoMuted: true});
3324
3487
 
3325
- // and no other local mute requests were sent to Locus
3326
- assert.calledTwice(locusMediaRequestStub);
3327
- });
3488
+ // and no other local mute requests were sent to Locus
3489
+ assert.calledTwice(locusMediaRequestStub);
3490
+ });
3328
3491
 
3329
- it('updateMedia() enables media when stream is published', async () => {
3330
- await addMedia(false, fakeMicrophoneStream);
3492
+ it('updateMedia() enables media when stream is published', async () => {
3493
+ await addMedia(false, fakeMicrophoneStream);
3331
3494
 
3332
- await meeting.updateMedia({audioEnabled: true});
3333
- await stableState();
3495
+ await meeting.updateMedia({audioEnabled: true});
3496
+ await stableState();
3334
3497
 
3335
- // the roap media connection should be updated
3336
- checkAudioEnabled(fakeMicrophoneStream, 'sendrecv');
3498
+ // the roap media connection should be updated
3499
+ checkAudioEnabled(fakeMicrophoneStream, 'sendrecv');
3337
3500
 
3338
- checkLocalMuteSentToLocus({audioMuted: false, videoMuted: true});
3501
+ checkLocalMuteSentToLocus({audioMuted: false, videoMuted: true});
3339
3502
 
3340
- locusMediaRequestStub.resetHistory();
3503
+ locusMediaRequestStub.resetHistory();
3341
3504
 
3342
- // and that would trigger a new offer so we simulate it happening
3343
- await simulateRoapOffer();
3505
+ // and that would trigger a new offer so we simulate it happening
3506
+ await simulateRoapOffer();
3344
3507
 
3345
- // check SDP offer was sent with the right audioMuted/videoMuted values
3346
- checkSdpOfferSent({audioMuted: false, videoMuted: true});
3508
+ // check SDP offer was sent with the right audioMuted/videoMuted values
3509
+ checkSdpOfferSent({audioMuted: false, videoMuted: true});
3347
3510
 
3348
- // simulate OK being sent in response to remote answer being received
3349
- await simulateRoapOk();
3511
+ // simulate OK being sent in response to remote answer being received
3512
+ await simulateRoapOk();
3350
3513
 
3351
- // check OK was sent with the right audioMuted/videoMuted values
3352
- checkOkSent({audioMuted: false, videoMuted: true});
3514
+ // check OK was sent with the right audioMuted/videoMuted values
3515
+ checkOkSent({audioMuted: false, videoMuted: true});
3353
3516
 
3354
- // and no other local mute requests were sent to Locus
3355
- assert.calledTwice(locusMediaRequestStub);
3517
+ // and no other local mute requests were sent to Locus
3518
+ assert.calledTwice(locusMediaRequestStub);
3519
+ });
3356
3520
  });
3357
- });
3358
3521
 
3359
- [
3360
- {mute: true, title: 'muting a track before confluence is created'},
3361
- {mute: false, title: 'unmuting a track before confluence is created'}
3362
- ].forEach(({mute, title}) =>
3363
- it(title, async () => {
3364
- // initialize the microphone mute state to opposite of what we do in the test
3365
- fakeMicrophoneStream.muted = !mute;
3522
+ [
3523
+ {mute: true, title: 'muting a track before confluence is created'},
3524
+ {mute: false, title: 'unmuting a track before confluence is created'},
3525
+ ].forEach(({mute, title}) =>
3526
+ it(title, async () => {
3527
+ // initialize the microphone mute state to opposite of what we do in the test
3528
+ fakeMicrophoneStream.muted = !mute;
3366
3529
 
3367
- await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}});
3368
- await stableState();
3530
+ await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}});
3531
+ await stableState();
3369
3532
 
3370
- resetHistory();
3533
+ resetHistory();
3371
3534
 
3372
- assert.equal(fakeMicrophoneStream.on.getCall(0).args[0], StreamEventNames.MuteStateChange);
3373
- const mutedListener = fakeMicrophoneStream.on.getCall(0).args[1];
3374
- // simulate track being muted
3375
- mutedListener(mute);
3535
+ assert.equal(
3536
+ fakeMicrophoneStream.on.getCall(0).args[0],
3537
+ StreamEventNames.MuteStateChange
3538
+ );
3539
+ const mutedListener = fakeMicrophoneStream.on.getCall(0).args[1];
3540
+ // simulate track being muted
3541
+ mutedListener(mute);
3376
3542
 
3377
- await stableState();
3543
+ await stableState();
3378
3544
 
3379
- // nothing should happen
3380
- assert.notCalled(locusMediaRequestStub);
3381
- assert.notCalled(fakeRoapMediaConnection.update);
3545
+ // nothing should happen
3546
+ assert.notCalled(locusMediaRequestStub);
3547
+ assert.notCalled(fakeRoapMediaConnection.update);
3382
3548
 
3383
- // now simulate roap offer and ok
3384
- await simulateRoapOffer();
3385
- await simulateRoapOk();
3549
+ // now simulate roap offer and ok
3550
+ await simulateRoapOffer();
3551
+ await simulateRoapOk();
3386
3552
 
3387
- // it should be sent with the right mute status
3388
- checkSdpOfferSent({audioMuted: mute, videoMuted: true});
3389
- // check OK was sent with the right audioMuted/videoMuted values
3390
- checkOkSent({audioMuted: mute, videoMuted: true});
3553
+ // it should be sent with the right mute status
3554
+ checkSdpOfferSent({audioMuted: mute, videoMuted: true});
3555
+ // check OK was sent with the right audioMuted/videoMuted values
3556
+ checkOkSent({audioMuted: mute, videoMuted: true});
3391
3557
 
3392
- // nothing else should happen
3393
- assert.calledTwice(locusMediaRequestStub);
3394
- assert.notCalled(fakeRoapMediaConnection.update);
3395
- })
3396
- );
3397
- }));
3558
+ // nothing else should happen
3559
+ assert.calledTwice(locusMediaRequestStub);
3560
+ assert.notCalled(fakeRoapMediaConnection.update);
3561
+ })
3562
+ );
3563
+ })
3564
+ );
3398
3565
 
3399
3566
  describe('#acknowledge', () => {
3400
3567
  it('should have #acknowledge', () => {
@@ -3625,6 +3792,7 @@ describe('plugin-meetings', () => {
3625
3792
  it('should have #requestScreenShareFloor', () => {
3626
3793
  assert.exists(meeting.requestScreenShareFloor);
3627
3794
  });
3795
+
3628
3796
  beforeEach(() => {
3629
3797
  meeting.locusInfo.mediaShares = [{name: 'content', url: url1}];
3630
3798
  meeting.locusInfo.self = {url: url1};
@@ -3632,13 +3800,47 @@ describe('plugin-meetings', () => {
3632
3800
  meeting.mediaProperties.shareVideoStream = {};
3633
3801
  meeting.mediaProperties.mediaDirection.sendShare = true;
3634
3802
  meeting.state = 'JOINED';
3803
+ meeting.localShareInstanceId = '1234-5678';
3635
3804
  });
3805
+
3806
+ afterEach(() => {
3807
+ sinon.restore();
3808
+ });
3809
+
3636
3810
  it('should send the share', async () => {
3637
3811
  const share = meeting.requestScreenShareFloor();
3638
3812
 
3639
3813
  assert.exists(share.then);
3640
3814
  await share;
3641
3815
  assert.calledOnce(meeting.meetingRequest.changeMeetingFloor);
3816
+
3817
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
3818
+ name: 'client.share.floor-grant.request',
3819
+ payload: {mediaType: 'share', shareInstanceId: '1234-5678'},
3820
+ options: {meetingId: meeting.id},
3821
+ });
3822
+ });
3823
+
3824
+ it('should submit expected metric on failure', async () => {
3825
+ const error = new Error('forced');
3826
+
3827
+ meeting.meetingRequest.changeMeetingFloor = sinon.stub().returns(Promise.reject(error));
3828
+ const getChangeMeetingFloorErrorPayloadSpy = sinon
3829
+ .stub(MeetingUtil, 'getChangeMeetingFloorErrorPayload')
3830
+ .returns('foo');
3831
+
3832
+ await meeting.requestScreenShareFloor().catch((err) => {
3833
+ assert.equal(err, error);
3834
+ });
3835
+
3836
+ assert.calledWith(getChangeMeetingFloorErrorPayloadSpy, 'forced');
3837
+
3838
+ // ensure the expected CA share metric is submitted
3839
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
3840
+ name: 'client.share.floor-granted.local',
3841
+ payload: {mediaType: 'share', errors: 'foo', shareInstanceId: '1234-5678'},
3842
+ options: {meetingId: meeting.id},
3843
+ });
3642
3844
  });
3643
3845
  });
3644
3846
 
@@ -3691,13 +3893,13 @@ describe('plugin-meetings', () => {
3691
3893
  outputStream: {
3692
3894
  getTracks: () => {
3693
3895
  return [{id: 'fake underlying track'}];
3694
- }
3695
- }
3896
+ },
3897
+ },
3696
3898
  });
3697
3899
  beforeEach(() => {
3698
3900
  sandbox = sinon.createSandbox();
3699
- meeting.audio = { enable: sinon.stub()};
3700
- meeting.video = { enable: sinon.stub()};
3901
+ meeting.audio = {enable: sinon.stub()};
3902
+ meeting.video = {enable: sinon.stub()};
3701
3903
  meeting.mediaProperties.audioStream = createFakeLocalStream();
3702
3904
  meeting.mediaProperties.videoStream = createFakeLocalStream();
3703
3905
  meeting.mediaProperties.shareVideoStream = createFakeLocalStream();
@@ -3709,12 +3911,15 @@ describe('plugin-meetings', () => {
3709
3911
  receiveAudio: true,
3710
3912
  receiveVideo: true,
3711
3913
  receiveShare: true,
3712
- }
3914
+ };
3713
3915
  const fakeMultistreamRoapMediaConnection = {
3714
- createSendSlot: () => {}
3916
+ createSendSlot: () => {},
3715
3917
  };
3716
- sinon.stub(fakeMultistreamRoapMediaConnection,'createSendSlot').returns({active: true});
3717
- meeting.sendSlotManager.createSlot(fakeMultistreamRoapMediaConnection,MediaType.AudioMain);
3918
+ sinon.stub(fakeMultistreamRoapMediaConnection, 'createSendSlot').returns({active: true});
3919
+ meeting.sendSlotManager.createSlot(
3920
+ fakeMultistreamRoapMediaConnection,
3921
+ MediaType.AudioMain
3922
+ );
3718
3923
  });
3719
3924
 
3720
3925
  afterEach(() => {
@@ -3771,23 +3976,22 @@ describe('plugin-meetings', () => {
3771
3976
  // and check that update is called with the original args
3772
3977
  assert.calledOnce(meeting.mediaProperties.webrtcMediaConnection.update);
3773
3978
 
3774
- assert.calledWith(
3775
- meeting.mediaProperties.webrtcMediaConnection.update,
3776
- {
3777
- localTracks: {
3778
- audio: meeting.mediaProperties.audioStream.outputStream.getTracks()[0],
3779
- video: meeting.mediaProperties.videoStream.outputStream.getTracks()[0],
3780
- screenShareVideo: meeting.mediaProperties.shareVideoStream.outputStream.getTracks()[0],
3781
- screenShareAudio: meeting.mediaProperties.shareVideoStream.outputStream.getTracks()[0],
3782
- },
3783
- direction: {
3784
- audio: 'inactive',
3785
- video: 'inactive',
3786
- screenShareVideo: 'sendrecv',
3787
- },
3788
- remoteQualityLevel: 'HIGH',
3789
- }
3790
- );
3979
+ assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.update, {
3980
+ localTracks: {
3981
+ audio: meeting.mediaProperties.audioStream.outputStream.getTracks()[0],
3982
+ video: meeting.mediaProperties.videoStream.outputStream.getTracks()[0],
3983
+ screenShareVideo:
3984
+ meeting.mediaProperties.shareVideoStream.outputStream.getTracks()[0],
3985
+ screenShareAudio:
3986
+ meeting.mediaProperties.shareVideoStream.outputStream.getTracks()[0],
3987
+ },
3988
+ direction: {
3989
+ audio: 'inactive',
3990
+ video: 'inactive',
3991
+ screenShareVideo: 'sendrecv',
3992
+ },
3993
+ remoteQualityLevel: 'HIGH',
3994
+ });
3791
3995
  assert.isTrue(myPromiseResolved);
3792
3996
  });
3793
3997
  });
@@ -3805,15 +4009,13 @@ describe('plugin-meetings', () => {
3805
4009
  receiveVideo: true,
3806
4010
  };
3807
4011
  meeting.mediaProperties.mediaDirection = mediaDirection;
3808
- meeting.mediaProperties.remoteVideoStream = sinon
3809
- .stub()
3810
- .returns({
3811
- outputStream: {
3812
- getTracks: () => {
3813
- id: 'some mock id'
3814
- }
3815
- }
3816
- });
4012
+ meeting.mediaProperties.remoteVideoStream = sinon.stub().returns({
4013
+ outputStream: {
4014
+ getTracks: () => {
4015
+ id: 'some mock id';
4016
+ },
4017
+ },
4018
+ });
3817
4019
 
3818
4020
  meeting.meetingRequest.changeVideoLayoutDebounced = sinon
3819
4021
  .stub()
@@ -3890,7 +4092,9 @@ describe('plugin-meetings', () => {
3890
4092
  });
3891
4093
 
3892
4094
  meeting.mediaProperties.mediaDirection.receiveShare = true;
3893
- meeting.mediaProperties.remoteShareStream = sinon.stub().returns({mockTrack: 'mockTrack'});
4095
+ meeting.mediaProperties.remoteShareStream = sinon
4096
+ .stub()
4097
+ .returns({mockTrack: 'mockTrack'});
3894
4098
 
3895
4099
  // now call it again with just content
3896
4100
  await meeting.changeVideoLayout(layoutTypeSingle, {content: {width: 500, height: 600}});
@@ -3959,7 +4163,9 @@ describe('plugin-meetings', () => {
3959
4163
 
3960
4164
  it('does not call changeVideoLayoutDebounced if renderInfo content changes only very slightly', async () => {
3961
4165
  meeting.mediaProperties.mediaDirection.receiveShare = true;
3962
- meeting.mediaProperties.remoteShareStream = sinon.stub().returns({mockTrack: 'mockTrack'});
4166
+ meeting.mediaProperties.remoteShareStream = sinon
4167
+ .stub()
4168
+ .returns({mockTrack: 'mockTrack'});
3963
4169
 
3964
4170
  await meeting.changeVideoLayout(layoutTypeSingle, {
3965
4171
  main: {width: 500, height: 510},
@@ -3999,7 +4205,9 @@ describe('plugin-meetings', () => {
3999
4205
 
4000
4206
  it('rounds the width and height values to nearest integers', async () => {
4001
4207
  meeting.mediaProperties.mediaDirection.receiveShare = true;
4002
- meeting.mediaProperties.remoteShareStream = sinon.stub().returns({mockTrack: 'mockTrack'});
4208
+ meeting.mediaProperties.remoteShareStream = sinon
4209
+ .stub()
4210
+ .returns({mockTrack: 'mockTrack'});
4003
4211
 
4004
4212
  await meeting.changeVideoLayout(layoutTypeSingle, {
4005
4213
  main: {width: 500.5, height: 510.09},
@@ -4265,11 +4473,7 @@ describe('plugin-meetings', () => {
4265
4473
  FAKE_OPTIONS
4266
4474
  );
4267
4475
 
4268
- assert.calledWith(
4269
- meeting.parseMeetingInfo,
4270
- {body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL},
4271
- FAKE_DESTINATION
4272
- );
4476
+ assert.calledWith(meeting.parseMeetingInfo, FAKE_MEETING_INFO, FAKE_DESTINATION);
4273
4477
  assert.deepEqual(meeting.meetingInfo, {
4274
4478
  ...FAKE_MEETING_INFO,
4275
4479
  meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
@@ -4323,11 +4527,7 @@ describe('plugin-meetings', () => {
4323
4527
  );
4324
4528
 
4325
4529
  // parseMeeting info
4326
- assert.calledWith(
4327
- meeting.parseMeetingInfo,
4328
- {body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL},
4329
- FAKE_DESTINATION
4330
- );
4530
+ assert.calledWith(meeting.parseMeetingInfo, FAKE_MEETING_INFO, FAKE_DESTINATION);
4331
4531
 
4332
4532
  assert.deepEqual(meeting.meetingInfo, {
4333
4533
  ...FAKE_MEETING_INFO,
@@ -4463,7 +4663,7 @@ describe('plugin-meetings', () => {
4463
4663
  await assert.isRejected(
4464
4664
  meeting.fetchMeetingInfo({
4465
4665
  password: 'aaa',
4466
- sendCAevents: true
4666
+ sendCAevents: true,
4467
4667
  }),
4468
4668
  CaptchaError
4469
4669
  );
@@ -4569,62 +4769,222 @@ describe('plugin-meetings', () => {
4569
4769
  assert.equal(meeting.requiredCaptcha, null);
4570
4770
  });
4571
4771
 
4572
- it('refreshes captcha when captcha was required and we received 403 error code', async () => {
4573
- meeting.destination = FAKE_DESTINATION;
4574
- meeting.destinationType = FAKE_TYPE;
4575
- const refreshedCaptcha = {
4576
- captchaID: FAKE_WBXAPPAPI_CAPTCHA_INFO.captchaID,
4577
- verificationImageURL: FAKE_WBXAPPAPI_CAPTCHA_INFO.verificationImageURL,
4578
- verificationAudioURL: FAKE_WBXAPPAPI_CAPTCHA_INFO.verificationAudioURL,
4579
- };
4580
-
4772
+ it('refreshes captcha when captcha was required and we received 403 error code', async () => {
4773
+ meeting.destination = FAKE_DESTINATION;
4774
+ meeting.destinationType = FAKE_TYPE;
4775
+ const refreshedCaptcha = {
4776
+ captchaID: FAKE_WBXAPPAPI_CAPTCHA_INFO.captchaID,
4777
+ verificationImageURL: FAKE_WBXAPPAPI_CAPTCHA_INFO.verificationImageURL,
4778
+ verificationAudioURL: FAKE_WBXAPPAPI_CAPTCHA_INFO.verificationAudioURL,
4779
+ };
4780
+
4781
+ meeting.attrs.meetingInfoProvider = {
4782
+ fetchMeetingInfo: sinon
4783
+ .stub()
4784
+ .throws(new MeetingInfoV2PasswordError(403004, FAKE_MEETING_INFO)),
4785
+ };
4786
+ meeting.meetingRequest.refreshCaptcha = sinon.stub().returns(
4787
+ Promise.resolve({
4788
+ body: refreshedCaptcha,
4789
+ })
4790
+ );
4791
+ meeting.passwordStatus = PASSWORD_STATUS.REQUIRED;
4792
+ meeting.requiredCaptcha = FAKE_SDK_CAPTCHA_INFO;
4793
+ meeting.destination = FAKE_DESTINATION;
4794
+ meeting.destinationType = FAKE_TYPE;
4795
+
4796
+ await assert.isRejected(
4797
+ meeting.fetchMeetingInfo({
4798
+ password: 'aaa',
4799
+ captchaCode: 'bbb',
4800
+ sendCAevents: true,
4801
+ })
4802
+ );
4803
+
4804
+ assert.calledWith(
4805
+ meeting.attrs.meetingInfoProvider.fetchMeetingInfo,
4806
+ FAKE_DESTINATION,
4807
+ FAKE_TYPE,
4808
+ 'aaa',
4809
+ {code: 'bbb', id: FAKE_CAPTCHA_ID},
4810
+ undefined,
4811
+ 'locus-id',
4812
+ {},
4813
+ {meetingId: meeting.id, sendCAevents: true}
4814
+ );
4815
+
4816
+ assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
4817
+ assert.equal(
4818
+ meeting.meetingInfoFailureReason,
4819
+ MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD
4820
+ );
4821
+ assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
4822
+ assert.deepEqual(meeting.requiredCaptcha, {
4823
+ captchaId: refreshedCaptcha.captchaID,
4824
+ verificationImageURL: refreshedCaptcha.verificationImageURL,
4825
+ verificationAudioURL: refreshedCaptcha.verificationAudioURL,
4826
+ refreshURL: FAKE_SDK_CAPTCHA_INFO.refreshURL, // refresh url doesn't change
4827
+ });
4828
+ });
4829
+ });
4830
+
4831
+ describe('#injectMeetingInfo', () => {
4832
+ const FAKE_PASSWORD = '123456';
4833
+ const FAKE_CAPTCHA_CODE = '654321';
4834
+ const FAKE_DESTINATION = 'something@somecompany.com';
4835
+ const FAKE_TYPE = _SIP_URI_;
4836
+ const FAKE_INSTALLED_ORG_ID = '123456';
4837
+ const FAKE_MEETING_INFO_LOOKUP_URL = 'meetingLookupUrl';
4838
+
4839
+ const FAKE_SDK_CAPTCHA_INFO = {};
4840
+ const FAKE_MEETING_INFO = {
4841
+ conversationUrl: 'some_convo_url',
4842
+ locusUrl: 'some_locus_url',
4843
+ sipUrl: 'some_sip_url', // or sipMeetingUri
4844
+ meetingNumber: '123456', // this.config.experimental.enableUnifiedMeetings
4845
+ hostId: 'some_host_id', // this.owner;
4846
+ };
4847
+
4848
+ [
4849
+ {
4850
+ input: {
4851
+ meetingInfo: FAKE_MEETING_INFO,
4852
+ meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
4853
+ },
4854
+ expected: {
4855
+ meetingInfo: {
4856
+ ...FAKE_MEETING_INFO,
4857
+ meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
4858
+ },
4859
+ },
4860
+ },
4861
+ {
4862
+ input: {
4863
+ meetingInfo: undefined,
4864
+ meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
4865
+ },
4866
+ expected: {meetingInfo: null},
4867
+ },
4868
+ ,
4869
+ {
4870
+ input: {
4871
+ meetingInfo: FAKE_MEETING_INFO,
4872
+ meetingLookupUrl: undefined,
4873
+ },
4874
+ expected: {
4875
+ meetingInfo: {
4876
+ ...FAKE_MEETING_INFO,
4877
+ meetingLookupUrl: undefined,
4878
+ },
4879
+ },
4880
+ },
4881
+ ,
4882
+ {
4883
+ input: {
4884
+ meetingInfo: undefined,
4885
+ meetingLookupUrl: undefined,
4886
+ },
4887
+ expected: {meetingInfo: null},
4888
+ },
4889
+ ].forEach(({input, expected}) => {
4890
+ it(`calls meetingInfoProvider with all the right parameters and parses the result when ${JSON.stringify(
4891
+ input
4892
+ )}`, async () => {
4893
+ meeting.requiredCaptcha = FAKE_SDK_CAPTCHA_INFO;
4894
+ meeting.destination = FAKE_DESTINATION;
4895
+ meeting.destinationType = FAKE_TYPE;
4896
+ meeting.config.installedOrgID = FAKE_INSTALLED_ORG_ID;
4897
+ meeting.parseMeetingInfo = sinon.stub().returns(undefined);
4898
+ meeting.updateMeetingActions = sinon.stub().returns(undefined);
4899
+
4900
+ await meeting.injectMeetingInfo(
4901
+ input.meetingInfo,
4902
+ {sendCAevents: true},
4903
+ input.meetingLookupUrl
4904
+ );
4905
+
4906
+ assert.calledWith(meeting.parseMeetingInfo, input.meetingInfo, FAKE_DESTINATION);
4907
+ assert.deepEqual(meeting.meetingInfo, expected.meetingInfo);
4908
+ assert.equal(meeting.passwordStatus, PASSWORD_STATUS.NOT_REQUIRED);
4909
+ assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
4910
+ assert.equal(meeting.requiredCaptcha, null);
4911
+ assert.calledThrice(TriggerProxy.trigger);
4912
+ assert.calledWith(
4913
+ TriggerProxy.trigger,
4914
+ meeting,
4915
+ {file: 'meetings', function: 'fetchMeetingInfo'},
4916
+ 'meeting:meetingInfoAvailable'
4917
+ );
4918
+ assert.calledWith(meeting.updateMeetingActions);
4919
+ });
4920
+ });
4921
+
4922
+ it('fails if captchaCode is provided when captcha not needed', async () => {
4923
+ meeting.attrs.meetingInfoProvider = {
4924
+ fetchMeetingInfo: sinon.stub().resolves(),
4925
+ };
4926
+ meeting.requiredCaptcha = null;
4927
+ meeting.destination = FAKE_DESTINATION;
4928
+ meeting.destinationType = FAKE_TYPE;
4929
+
4930
+ await assert.isRejected(
4931
+ meeting.injectMeetingInfo(
4932
+ {},
4933
+ {
4934
+ captchaCode: FAKE_CAPTCHA_CODE,
4935
+ }
4936
+ ),
4937
+ Error,
4938
+ 'injectMeetingInfo() called with captchaCode when captcha was not required'
4939
+ );
4940
+
4941
+ assert.notCalled(meeting.attrs.meetingInfoProvider.fetchMeetingInfo);
4942
+ assert.calledTwice(TriggerProxy.trigger); //meetingInfoAvailable event not triggered
4943
+ assert.neverCalledWith(
4944
+ TriggerProxy.trigger,
4945
+ meeting,
4946
+ {file: 'meetings', function: 'fetchMeetingInfo'},
4947
+ 'meeting:meetingInfoAvailable'
4948
+ );
4949
+ });
4950
+
4951
+ it('fails if password is provided when not required', async () => {
4581
4952
  meeting.attrs.meetingInfoProvider = {
4582
- fetchMeetingInfo: sinon
4583
- .stub()
4584
- .throws(new MeetingInfoV2PasswordError(403004, FAKE_MEETING_INFO)),
4953
+ fetchMeetingInfo: sinon.stub().resolves(),
4585
4954
  };
4586
- meeting.meetingRequest.refreshCaptcha = sinon.stub().returns(
4587
- Promise.resolve({
4588
- body: refreshedCaptcha,
4589
- })
4590
- );
4591
- meeting.passwordStatus = PASSWORD_STATUS.REQUIRED;
4592
- meeting.requiredCaptcha = FAKE_SDK_CAPTCHA_INFO;
4955
+ meeting.passwordStatus = PASSWORD_STATUS.NOT_REQUIRED;
4593
4956
  meeting.destination = FAKE_DESTINATION;
4594
4957
  meeting.destinationType = FAKE_TYPE;
4595
4958
 
4596
4959
  await assert.isRejected(
4597
- meeting.fetchMeetingInfo({
4598
- password: 'aaa',
4599
- captchaCode: 'bbb',
4600
- sendCAevents: true,
4601
- })
4960
+ meeting.injectMeetingInfo(
4961
+ {},
4962
+ {
4963
+ password: FAKE_PASSWORD,
4964
+ }
4965
+ ),
4966
+ Error,
4967
+ 'injectMeetingInfo() called with password when password was not required'
4602
4968
  );
4603
4969
 
4604
- assert.calledWith(
4605
- meeting.attrs.meetingInfoProvider.fetchMeetingInfo,
4606
- FAKE_DESTINATION,
4607
- FAKE_TYPE,
4608
- 'aaa',
4609
- {code: 'bbb', id: FAKE_CAPTCHA_ID},
4610
- undefined,
4611
- 'locus-id',
4612
- {},
4613
- {meetingId: meeting.id, sendCAevents: true}
4970
+ assert.notCalled(meeting.attrs.meetingInfoProvider.fetchMeetingInfo);
4971
+ assert.calledTwice(TriggerProxy.trigger); //meetingInfoAvailable event not triggered
4972
+ assert.neverCalledWith(
4973
+ TriggerProxy.trigger,
4974
+ meeting,
4975
+ {file: 'meetings', function: 'fetchMeetingInfo'},
4976
+ 'meeting:meetingInfoAvailable'
4614
4977
  );
4978
+ });
4615
4979
 
4616
- assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
4617
- assert.equal(
4618
- meeting.meetingInfoFailureReason,
4619
- MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD
4620
- );
4621
- assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
4622
- assert.deepEqual(meeting.requiredCaptcha, {
4623
- captchaId: refreshedCaptcha.captchaID,
4624
- verificationImageURL: refreshedCaptcha.verificationImageURL,
4625
- verificationAudioURL: refreshedCaptcha.verificationAudioURL,
4626
- refreshURL: FAKE_SDK_CAPTCHA_INFO.refreshURL, // refresh url doesn't change
4980
+ it('should clean the fetch meeting info timeout', async () => {
4981
+ meeting.fetchMeetingInfoTimeoutId = 42; // pending delayed request
4982
+
4983
+ await meeting.injectMeetingInfo(FAKE_MEETING_INFO, {
4984
+ sendCAevents: true,
4627
4985
  });
4986
+
4987
+ assert.equal(meeting.fetchMeetingInfoTimeoutId, undefined);
4628
4988
  });
4629
4989
  });
4630
4990
 
@@ -4648,9 +5008,9 @@ describe('plugin-meetings', () => {
4648
5008
  meeting.destination = 'meeting-destination';
4649
5009
  meeting.destinationType = 'meeting-destination-type';
4650
5010
  meeting.updateMeetingActions = sinon.stub().returns(undefined);
4651
-
5011
+
4652
5012
  meeting.meetingInfoExtraParams = {
4653
- extraParam1: 'value1'
5013
+ extraParam1: 'value1',
4654
5014
  };
4655
5015
  meeting.attrs.meetingInfoProvider = {
4656
5016
  fetchMeetingInfo: sinon
@@ -4685,7 +5045,7 @@ describe('plugin-meetings', () => {
4685
5045
  );
4686
5046
  assert.deepEqual(meeting.meetingInfo, {
4687
5047
  ...FAKE_MEETING_INFO,
4688
- meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL
5048
+ meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
4689
5049
  });
4690
5050
  assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
4691
5051
  assert.equal(meeting.requiredCaptcha, null);
@@ -4700,7 +5060,9 @@ describe('plugin-meetings', () => {
4700
5060
  assert.calledWith(meeting.updateMeetingActions);
4701
5061
 
4702
5062
  assert.calledWith(
4703
- Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH, {
5063
+ Metrics.sendBehavioralMetric,
5064
+ BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH,
5065
+ {
4704
5066
  correlationId: meeting.correlationId,
4705
5067
  timeLeft: FAKE_TIMESTAMPS.timeLeft,
4706
5068
  expiryTime: FAKE_TIMESTAMPS.expiryTime,
@@ -4728,7 +5090,7 @@ describe('plugin-meetings', () => {
4728
5090
  );
4729
5091
  assert.deepEqual(meeting.meetingInfo, {
4730
5092
  ...FAKE_MEETING_INFO,
4731
- meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL
5093
+ meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
4732
5094
  });
4733
5095
  assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
4734
5096
  assert.equal(meeting.requiredCaptcha, null);
@@ -4743,7 +5105,9 @@ describe('plugin-meetings', () => {
4743
5105
  assert.calledWith(meeting.updateMeetingActions);
4744
5106
 
4745
5107
  assert.calledWith(
4746
- Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH, {
5108
+ Metrics.sendBehavioralMetric,
5109
+ BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH,
5110
+ {
4747
5111
  correlationId: meeting.correlationId,
4748
5112
  timeLeft: undefined,
4749
5113
  expiryTime: undefined,
@@ -4774,13 +5138,13 @@ describe('plugin-meetings', () => {
4774
5138
  'locus-id',
4775
5139
  {
4776
5140
  extraParam1: 'value1',
4777
- permissionToken: FAKE_PERMISSION_TOKEN
5141
+ permissionToken: FAKE_PERMISSION_TOKEN,
4778
5142
  },
4779
5143
  {meetingId: meeting.id, sendCAevents: true}
4780
5144
  );
4781
5145
  assert.deepEqual(meeting.meetingInfo, {
4782
5146
  ...FAKE_MEETING_INFO,
4783
- meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL
5147
+ meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
4784
5148
  });
4785
5149
  assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
4786
5150
  assert.equal(meeting.requiredCaptcha, null);
@@ -4795,7 +5159,9 @@ describe('plugin-meetings', () => {
4795
5159
  assert.calledWith(meeting.updateMeetingActions);
4796
5160
 
4797
5161
  assert.calledWith(
4798
- Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH, {
5162
+ Metrics.sendBehavioralMetric,
5163
+ BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH,
5164
+ {
4799
5165
  correlationId: meeting.correlationId,
4800
5166
  timeLeft: FAKE_TIMESTAMPS.timeLeft,
4801
5167
  expiryTime: FAKE_TIMESTAMPS.expiryTime,
@@ -4824,9 +5190,12 @@ describe('plugin-meetings', () => {
4824
5190
  assert.calledWith(meeting.updateMeetingActions);
4825
5191
 
4826
5192
  assert.calledWith(
4827
- Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH_ERROR, {
5193
+ Metrics.sendBehavioralMetric,
5194
+ BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH_ERROR,
5195
+ {
4828
5196
  correlationId: meeting.correlationId,
4829
- reason: 'Not allowed to execute the function, some properties on server, or local client state do not allow you to complete this action.',
5197
+ reason:
5198
+ 'Not allowed to execute the function, some properties on server, or local client state do not allow you to complete this action.',
4830
5199
  stack: sinon.match.any,
4831
5200
  }
4832
5201
  );
@@ -4845,13 +5214,18 @@ describe('plugin-meetings', () => {
4845
5214
  assert.deepEqual(meeting.meetingInfo, {
4846
5215
  ...FAKE_MEETING_INFO,
4847
5216
  });
4848
- assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD);
5217
+ assert.equal(
5218
+ meeting.meetingInfoFailureReason,
5219
+ MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD
5220
+ );
4849
5221
  assert.equal(meeting.requiredCaptcha, null);
4850
5222
  assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
4851
5223
  assert.calledWith(meeting.updateMeetingActions);
4852
5224
 
4853
5225
  assert.calledWith(
4854
- Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH_ERROR, {
5226
+ Metrics.sendBehavioralMetric,
5227
+ BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH_ERROR,
5228
+ {
4855
5229
  correlationId: meeting.correlationId,
4856
5230
  reason: 'Password is required, please use verifyPassword()',
4857
5231
  stack: sinon.match.any,
@@ -4875,13 +5249,18 @@ describe('plugin-meetings', () => {
4875
5249
  await assert.isRejected(meeting.refreshPermissionToken());
4876
5250
 
4877
5251
  assert.calledOnce(meeting.attrs.meetingInfoProvider.fetchMeetingInfo);
4878
- assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD);
5252
+ assert.equal(
5253
+ meeting.meetingInfoFailureReason,
5254
+ MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD
5255
+ );
4879
5256
  assert.equal(meeting.requiredCaptcha, FAKE_SDK_CAPTCHA_INFO);
4880
5257
  assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
4881
5258
  assert.calledWith(meeting.updateMeetingActions);
4882
5259
 
4883
5260
  assert.calledWith(
4884
- Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH_ERROR, {
5261
+ Metrics.sendBehavioralMetric,
5262
+ BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH_ERROR,
5263
+ {
4885
5264
  correlationId: meeting.correlationId,
4886
5265
  reason: 'Captcha is required.',
4887
5266
  stack: sinon.match.any,
@@ -5306,14 +5685,26 @@ describe('plugin-meetings', () => {
5306
5685
  describe('#updateCallStateForMetrics', () => {
5307
5686
  it('should update the callState, overriding existing values', () => {
5308
5687
  assert.deepEqual(meeting.callStateForMetrics, {correlationId});
5309
- meeting.updateCallStateForMetrics({correlationId: uuid1, joinTrigger: 'jt', loginType: 'lt'});
5310
- assert.deepEqual(meeting.callStateForMetrics, {correlationId: uuid1, joinTrigger: 'jt', loginType: 'lt'});
5688
+ meeting.updateCallStateForMetrics({
5689
+ correlationId: uuid1,
5690
+ joinTrigger: 'jt',
5691
+ loginType: 'lt',
5692
+ });
5693
+ assert.deepEqual(meeting.callStateForMetrics, {
5694
+ correlationId: uuid1,
5695
+ joinTrigger: 'jt',
5696
+ loginType: 'lt',
5697
+ });
5311
5698
  });
5312
5699
 
5313
5700
  it('should update the callState, keeping non-supplied values', () => {
5314
5701
  assert.deepEqual(meeting.callStateForMetrics, {correlationId});
5315
5702
  meeting.updateCallStateForMetrics({joinTrigger: 'jt', loginType: 'lt'});
5316
- assert.deepEqual(meeting.callStateForMetrics, {correlationId, joinTrigger: 'jt', loginType: 'lt'});
5703
+ assert.deepEqual(meeting.callStateForMetrics, {
5704
+ correlationId,
5705
+ joinTrigger: 'jt',
5706
+ loginType: 'lt',
5707
+ });
5317
5708
  });
5318
5709
  });
5319
5710
 
@@ -5327,35 +5718,35 @@ describe('plugin-meetings', () => {
5327
5718
  beforeEach(() => {
5328
5719
  audioStream = {
5329
5720
  getSettings: sinon.stub().returns({
5330
- deviceId: 'some device id'
5721
+ deviceId: 'some device id',
5331
5722
  }),
5332
5723
  on: sinon.stub(),
5333
5724
  off: sinon.stub(),
5334
- }
5725
+ };
5335
5726
 
5336
5727
  videoStream = {
5337
5728
  getSettings: sinon.stub().returns({
5338
- deviceId: 'some device id'
5729
+ deviceId: 'some device id',
5339
5730
  }),
5340
5731
  on: sinon.stub(),
5341
5732
  off: sinon.stub(),
5342
- }
5733
+ };
5343
5734
 
5344
5735
  audioShareStream = {
5345
5736
  on: sinon.stub(),
5346
5737
  off: sinon.stub(),
5347
5738
  getSettings: sinon.stub().returns({
5348
- deviceId: 'some device id'
5739
+ deviceId: 'some device id',
5349
5740
  }),
5350
- }
5741
+ };
5351
5742
 
5352
5743
  videoShareStream = {
5353
5744
  on: sinon.stub(),
5354
5745
  off: sinon.stub(),
5355
5746
  getSettings: sinon.stub().returns({
5356
- deviceId: 'some device id'
5747
+ deviceId: 'some device id',
5357
5748
  }),
5358
- }
5749
+ };
5359
5750
 
5360
5751
  meeting.requestScreenShareFloor = sinon.stub().resolves({});
5361
5752
  meeting.releaseScreenShareFloor = sinon.stub().resolves({});
@@ -5366,20 +5757,32 @@ describe('plugin-meetings', () => {
5366
5757
  };
5367
5758
  meeting.isMultistream = true;
5368
5759
  meeting.mediaProperties.webrtcMediaConnection = {};
5369
- meeting.audio = { handleLocalStreamChange: sinon.stub()};
5370
- meeting.video = { handleLocalStreamChange: sinon.stub()};
5760
+ meeting.audio = {handleLocalStreamChange: sinon.stub()};
5761
+ meeting.video = {handleLocalStreamChange: sinon.stub()};
5371
5762
  fakeMultistreamRoapMediaConnection = {
5372
5763
  createSendSlot: () => {
5373
5764
  return {
5374
5765
  publishStream: sinon.stub(),
5375
5766
  unpublishStream: sinon.stub(),
5376
- }
5377
- }
5378
- }
5379
- meeting.sendSlotManager.createSlot(fakeMultistreamRoapMediaConnection, MediaType.VideoSlides);
5380
- meeting.sendSlotManager.createSlot(fakeMultistreamRoapMediaConnection, MediaType.AudioSlides);
5381
- meeting.sendSlotManager.createSlot(fakeMultistreamRoapMediaConnection, MediaType.AudioMain);
5382
- meeting.sendSlotManager.createSlot(fakeMultistreamRoapMediaConnection, MediaType.VideoMain);
5767
+ };
5768
+ },
5769
+ };
5770
+ meeting.sendSlotManager.createSlot(
5771
+ fakeMultistreamRoapMediaConnection,
5772
+ MediaType.VideoSlides
5773
+ );
5774
+ meeting.sendSlotManager.createSlot(
5775
+ fakeMultistreamRoapMediaConnection,
5776
+ MediaType.AudioSlides
5777
+ );
5778
+ meeting.sendSlotManager.createSlot(
5779
+ fakeMultistreamRoapMediaConnection,
5780
+ MediaType.AudioMain
5781
+ );
5782
+ meeting.sendSlotManager.createSlot(
5783
+ fakeMultistreamRoapMediaConnection,
5784
+ MediaType.VideoMain
5785
+ );
5383
5786
  });
5384
5787
  afterEach(() => {
5385
5788
  sinon.restore();
@@ -5415,16 +5818,22 @@ describe('plugin-meetings', () => {
5415
5818
  const checkScreenShareVideoPublished = (stream) => {
5416
5819
  assert.calledOnce(meeting.requestScreenShareFloor);
5417
5820
 
5418
- assert.calledWith(
5419
- meeting.sendSlotManager.getSlot(MediaType.VideoSlides).publishStream,
5420
- stream
5421
- );
5422
- assert.equal(meeting.mediaProperties.shareVideoStream, stream);
5821
+ // ensure the CA share metrics are submitted
5822
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
5823
+ name: 'client.share.initiated',
5824
+ payload: {mediaType: 'share', shareInstanceId: meeting.localShareInstanceId},
5825
+ options: {meetingId: meeting.id},
5826
+ });
5423
5827
  assert.equal(meeting.mediaProperties.mediaDirection.sendShare, true);
5424
5828
  };
5425
5829
 
5426
5830
  const checkScreenShareAudioPublished = (stream) => {
5427
- assert.calledOnce(meeting.requestScreenShareFloor);
5831
+ // ensure the CA share metrics are submitted
5832
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
5833
+ name: 'client.share.initiated',
5834
+ payload: {mediaType: 'share', shareInstanceId: meeting.localShareInstanceId},
5835
+ options: {meetingId: meeting.id},
5836
+ });
5428
5837
 
5429
5838
  assert.calledWith(
5430
5839
  meeting.sendSlotManager.getSlot(MediaType.AudioSlides).publishStream,
@@ -5503,18 +5912,14 @@ describe('plugin-meetings', () => {
5503
5912
  });
5504
5913
 
5505
5914
  const checkAudioUnpublished = () => {
5506
- assert.calledOnce(
5507
- meeting.sendSlotManager.getSlot(MediaType.AudioMain).unpublishStream
5508
- );
5915
+ assert.calledOnce(meeting.sendSlotManager.getSlot(MediaType.AudioMain).unpublishStream);
5509
5916
 
5510
5917
  assert.equal(meeting.mediaProperties.audioStream, null);
5511
5918
  assert.equal(meeting.mediaProperties.mediaDirection.sendAudio, 'fake value');
5512
5919
  };
5513
5920
 
5514
5921
  const checkVideoUnpublished = () => {
5515
- assert.calledOnce(
5516
- meeting.sendSlotManager.getSlot(MediaType.VideoMain).unpublishStream
5517
- );
5922
+ assert.calledOnce(meeting.sendSlotManager.getSlot(MediaType.VideoMain).unpublishStream);
5518
5923
 
5519
5924
  assert.equal(meeting.mediaProperties.videoStream, null);
5520
5925
  assert.equal(meeting.mediaProperties.mediaDirection.sendVideo, 'fake value');
@@ -5547,12 +5952,22 @@ describe('plugin-meetings', () => {
5547
5952
  it('fails if there is no media connection', async () => {
5548
5953
  meeting.mediaProperties.webrtcMediaConnection = undefined;
5549
5954
  await assert.isRejected(
5550
- meeting.unpublishStreams([audioStream, videoStream, videoShareStream, audioShareStream])
5955
+ meeting.unpublishStreams([
5956
+ audioStream,
5957
+ videoStream,
5958
+ videoShareStream,
5959
+ audioShareStream,
5960
+ ])
5551
5961
  );
5552
5962
  });
5553
5963
 
5554
5964
  it('un-publishes the streams correctly (all 4 together)', async () => {
5555
- await meeting.unpublishStreams([audioStream, videoStream, videoShareStream, audioShareStream]);
5965
+ await meeting.unpublishStreams([
5966
+ audioStream,
5967
+ videoStream,
5968
+ videoShareStream,
5969
+ audioShareStream,
5970
+ ]);
5556
5971
 
5557
5972
  checkAudioUnpublished();
5558
5973
  checkVideoUnpublished();
@@ -5612,40 +6027,48 @@ describe('plugin-meetings', () => {
5612
6027
  return {
5613
6028
  setCodecParameters: sinon.stub().resolves(),
5614
6029
  deleteCodecParameters: sinon.stub().resolves(),
5615
- }
5616
- }
6030
+ };
6031
+ },
5617
6032
  };
5618
- meeting.sendSlotManager.createSlot(fakeMultistreamRoapMediaConnection, MediaType.AudioMain, false);
6033
+ meeting.sendSlotManager.createSlot(
6034
+ fakeMultistreamRoapMediaConnection,
6035
+ MediaType.AudioMain,
6036
+ false
6037
+ );
5619
6038
  meeting.mediaProperties.webrtcMediaConnection = {};
5620
6039
  });
5621
6040
  afterEach(() => {
5622
6041
  sinon.restore();
5623
6042
  });
5624
- [
5625
- {shouldEnableMusicMode: true},
5626
- {shouldEnableMusicMode: false},
5627
- ].forEach(({shouldEnableMusicMode}) => {
5628
- it(`fails if there is no media connection for shouldEnableMusicMode: ${shouldEnableMusicMode}`, async () => {
5629
- meeting.mediaProperties.webrtcMediaConnection = undefined;
5630
- await assert.isRejected(meeting.enableMusicMode(shouldEnableMusicMode));
5631
- });
5632
- });
6043
+ [{shouldEnableMusicMode: true}, {shouldEnableMusicMode: false}].forEach(
6044
+ ({shouldEnableMusicMode}) => {
6045
+ it(`fails if there is no media connection for shouldEnableMusicMode: ${shouldEnableMusicMode}`, async () => {
6046
+ meeting.mediaProperties.webrtcMediaConnection = undefined;
6047
+ await assert.isRejected(meeting.enableMusicMode(shouldEnableMusicMode));
6048
+ });
6049
+ }
6050
+ );
5633
6051
 
5634
6052
  it('should set the codec parameters when shouldEnableMusicMode is true', async () => {
5635
6053
  await meeting.enableMusicMode(true);
5636
- assert.calledOnceWithExactly(meeting.sendSlotManager.getSlot(MediaType.AudioMain).setCodecParameters, {
5637
- maxaveragebitrate: '64000',
5638
- maxplaybackrate: '48000',
5639
- });
5640
- assert.notCalled(meeting.sendSlotManager.getSlot(MediaType.AudioMain).deleteCodecParameters);
6054
+ assert.calledOnceWithExactly(
6055
+ meeting.sendSlotManager.getSlot(MediaType.AudioMain).setCodecParameters,
6056
+ {
6057
+ maxaveragebitrate: '64000',
6058
+ maxplaybackrate: '48000',
6059
+ }
6060
+ );
6061
+ assert.notCalled(
6062
+ meeting.sendSlotManager.getSlot(MediaType.AudioMain).deleteCodecParameters
6063
+ );
5641
6064
  });
5642
6065
 
5643
6066
  it('should set the codec parameters when shouldEnableMusicMode is false', async () => {
5644
6067
  await meeting.enableMusicMode(false);
5645
- assert.calledOnceWithExactly(meeting.sendSlotManager.getSlot(MediaType.AudioMain).deleteCodecParameters, [
5646
- 'maxaveragebitrate',
5647
- 'maxplaybackrate',
5648
- ]);
6068
+ assert.calledOnceWithExactly(
6069
+ meeting.sendSlotManager.getSlot(MediaType.AudioMain).deleteCodecParameters,
6070
+ ['maxaveragebitrate', 'maxplaybackrate']
6071
+ );
5649
6072
  assert.notCalled(meeting.sendSlotManager.getSlot(MediaType.AudioMain).setCodecParameters);
5650
6073
  });
5651
6074
  });
@@ -5656,8 +6079,8 @@ describe('plugin-meetings', () => {
5656
6079
  beforeEach(() => {
5657
6080
  const fakeMediaStream = () => {
5658
6081
  return {
5659
- id: 'fake stream'
5660
- }
6082
+ id: 'fake stream',
6083
+ };
5661
6084
  };
5662
6085
 
5663
6086
  sandbox = sinon.createSandbox();
@@ -5724,7 +6147,7 @@ describe('plugin-meetings', () => {
5724
6147
  } catch (err) {
5725
6148
  assert.fail('reconnect should not error after clean up');
5726
6149
  }
5727
- })
6150
+ });
5728
6151
 
5729
6152
  it('should trigger reconnection success and send CA metric', async () => {
5730
6153
  await meeting.reconnect();
@@ -5744,7 +6167,10 @@ describe('plugin-meetings', () => {
5744
6167
  meetingId: meeting.id,
5745
6168
  },
5746
6169
  });
5747
- assert.calledOnceWithExactly(meeting.reconnectionManager.setStatus, RECONNECTION.STATE.COMPLETE);
6170
+ assert.calledOnceWithExactly(
6171
+ meeting.reconnectionManager.setStatus,
6172
+ RECONNECTION.STATE.COMPLETE
6173
+ );
5748
6174
  });
5749
6175
 
5750
6176
  it('should reset after reconnection success', async () => {
@@ -5839,7 +6265,7 @@ describe('plugin-meetings', () => {
5839
6265
  let eventListeners;
5840
6266
  const fakeStream = {
5841
6267
  id: 'stream',
5842
- getTracks: () => [{ id: 'track', addEventListener: sinon.stub() }]
6268
+ getTracks: () => [{id: 'track', addEventListener: sinon.stub()}],
5843
6269
  };
5844
6270
 
5845
6271
  beforeEach(() => {
@@ -5906,7 +6332,7 @@ describe('plugin-meetings', () => {
5906
6332
  });
5907
6333
 
5908
6334
  assert.notCalled(webex.internal.newMetrics.submitClientEvent);
5909
- })
6335
+ });
5910
6336
 
5911
6337
  it('sends client.ice.start correctly when hasMediaConnectionConnectedAtLeastOnce = false', () => {
5912
6338
  meeting.hasMediaConnectionConnectedAtLeastOnce = false;
@@ -5922,7 +6348,7 @@ describe('plugin-meetings', () => {
5922
6348
  meetingId: meeting.id,
5923
6349
  },
5924
6350
  });
5925
- })
6351
+ });
5926
6352
  });
5927
6353
 
5928
6354
  describe('submitClientEvent on connectionSuccess', () => {
@@ -6050,22 +6476,17 @@ describe('plugin-meetings', () => {
6050
6476
 
6051
6477
  const checkBehavioralMetricSent = (hasMediaConnectionConnectedAtLeastOnce = false) => {
6052
6478
  assert.calledOnce(Metrics.sendBehavioralMetric);
6053
- assert.calledWith(
6054
- Metrics.sendBehavioralMetric,
6055
- BEHAVIORAL_METRICS.CONNECTION_FAILURE,
6056
- {
6057
- correlation_id: meeting.correlationId,
6058
- locus_id: meeting.locusUrl.split('/').pop(),
6059
- networkStatus: meeting.networkStatus,
6060
- hasMediaConnectionConnectedAtLeastOnce,
6061
- },
6062
- );
6479
+ assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.CONNECTION_FAILURE, {
6480
+ correlation_id: meeting.correlationId,
6481
+ locus_id: meeting.locusUrl.split('/').pop(),
6482
+ networkStatus: meeting.networkStatus,
6483
+ hasMediaConnectionConnectedAtLeastOnce,
6484
+ });
6063
6485
  };
6064
6486
 
6065
6487
  it('handles "Disconnected" state correctly when waitForIceReconnect resolves', async () => {
6066
6488
  meeting.reconnectionManager.waitForIceReconnect = sinon.stub().resolves();
6067
6489
 
6068
-
6069
6490
  mockDisconnectedEvent();
6070
6491
 
6071
6492
  await testUtils.flushPromises();
@@ -6079,14 +6500,13 @@ describe('plugin-meetings', () => {
6079
6500
 
6080
6501
  it('handles "Disconnected" state correctly when waitForIceReconnect rejects and hasMediaConnectionConnectedAtLeastOnce = true', async () => {
6081
6502
  const FAKE_ERROR = {fatal: true};
6082
- const getErrorPayloadForClientErrorCodeStub = webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode = sinon
6083
- .stub()
6084
- .returns(FAKE_ERROR);
6503
+ const getErrorPayloadForClientErrorCodeStub =
6504
+ (webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode =
6505
+ sinon.stub().returns(FAKE_ERROR));
6085
6506
  meeting.waitForMediaConnectionConnected = sinon.stub().resolves();
6086
6507
  meeting.reconnectionManager.waitForIceReconnect = sinon.stub().rejects();
6087
6508
  meeting.hasMediaConnectionConnectedAtLeastOnce = true;
6088
6509
 
6089
-
6090
6510
  mockDisconnectedEvent();
6091
6511
 
6092
6512
  await testUtils.flushPromises();
@@ -6101,7 +6521,6 @@ describe('plugin-meetings', () => {
6101
6521
  it('handles "Disconnected" state correctly when waitForIceReconnect rejects and hasMediaConnectionConnectedAtLeastOnce = false', async () => {
6102
6522
  meeting.reconnectionManager.waitForIceReconnect = sinon.stub().rejects();
6103
6523
 
6104
-
6105
6524
  mockDisconnectedEvent();
6106
6525
 
6107
6526
  await testUtils.flushPromises();
@@ -6115,7 +6534,6 @@ describe('plugin-meetings', () => {
6115
6534
  });
6116
6535
 
6117
6536
  describe('CONNECTION_STATE_CHANGED event when state = "Failed"', () => {
6118
-
6119
6537
  const mockFailedEvent = () => {
6120
6538
  meeting.setupMediaConnectionListeners();
6121
6539
  eventListeners[Event.CONNECTION_STATE_CHANGED]({
@@ -6125,16 +6543,12 @@ describe('plugin-meetings', () => {
6125
6543
 
6126
6544
  const checkBehavioralMetricSent = (hasMediaConnectionConnectedAtLeastOnce = false) => {
6127
6545
  assert.calledOnce(Metrics.sendBehavioralMetric);
6128
- assert.calledWith(
6129
- Metrics.sendBehavioralMetric,
6130
- BEHAVIORAL_METRICS.CONNECTION_FAILURE,
6131
- {
6132
- correlation_id: meeting.correlationId,
6133
- locus_id: meeting.locusUrl.split('/').pop(),
6134
- networkStatus: meeting.networkStatus,
6135
- hasMediaConnectionConnectedAtLeastOnce,
6136
- },
6137
- );
6546
+ assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.CONNECTION_FAILURE, {
6547
+ correlation_id: meeting.correlationId,
6548
+ locus_id: meeting.locusUrl.split('/').pop(),
6549
+ networkStatus: meeting.networkStatus,
6550
+ hasMediaConnectionConnectedAtLeastOnce,
6551
+ });
6138
6552
  };
6139
6553
 
6140
6554
  it('handles "Failed" state correctly when hasMediaConnectionConnectedAtLeastOnce = false', async () => {
@@ -6399,7 +6813,6 @@ describe('plugin-meetings', () => {
6399
6813
  sdp: 'fake sdp',
6400
6814
  tieBreaker: 12345,
6401
6815
  meeting,
6402
- reconnect: false,
6403
6816
  });
6404
6817
  assert.notCalled(meeting.roapMessageReceived);
6405
6818
  });
@@ -6426,14 +6839,13 @@ describe('plugin-meetings', () => {
6426
6839
  sdp: 'fake sdp',
6427
6840
  tieBreaker: 12345,
6428
6841
  meeting,
6429
- reconnect: false,
6430
6842
  });
6431
6843
  assert.calledWith(meeting.roapMessageReceived, fakeAnswer);
6432
6844
  });
6433
6845
 
6434
6846
  it('handles OFFER message correctly when request fails', async () => {
6435
6847
  const clock = sinon.useFakeTimers();
6436
- sinon.spy(clock, "clearTimeout");
6848
+ sinon.spy(clock, 'clearTimeout');
6437
6849
  meeting.deferSDPAnswer = {reject: sinon.stub()};
6438
6850
  meeting.sdpResponseTimer = '1234';
6439
6851
  sendRoapMediaRequestStub.rejects();
@@ -6456,7 +6868,6 @@ describe('plugin-meetings', () => {
6456
6868
  sdp: 'fake sdp',
6457
6869
  tieBreaker: 12345,
6458
6870
  meeting,
6459
- reconnect: false,
6460
6871
  });
6461
6872
  assert.notCalled(meeting.roapMessageReceived);
6462
6873
  assert.calledOnce(meeting.deferSDPAnswer.reject);
@@ -7041,41 +7452,6 @@ describe('plugin-meetings', () => {
7041
7452
  );
7042
7453
  });
7043
7454
 
7044
- it('listens to the timing that user joined into breakout', async () => {
7045
- const mainLocusUrl = 'mainLocusUrl123';
7046
-
7047
- meeting.meetingRequest.getLocusStatusByUrl = sinon.stub().returns(Promise.resolve());
7048
-
7049
- await meeting.locusInfo.emit(
7050
- {function: 'test', file: 'test'},
7051
- 'CONTROLS_JOIN_BREAKOUT_FROM_MAIN',
7052
- {mainLocusUrl}
7053
- );
7054
-
7055
- assert.calledOnceWithExactly(meeting.meetingRequest.getLocusStatusByUrl, mainLocusUrl);
7056
- const error = {statusCode: 403};
7057
- meeting.meetingRequest.getLocusStatusByUrl.rejects(error);
7058
- meeting.locusInfo.clearMainSessionLocusCache = sinon.stub();
7059
- await meeting.locusInfo.emit(
7060
- {function: 'test', file: 'test'},
7061
- 'CONTROLS_JOIN_BREAKOUT_FROM_MAIN',
7062
- {mainLocusUrl}
7063
- );
7064
-
7065
- assert.calledOnce(meeting.locusInfo.clearMainSessionLocusCache);
7066
-
7067
- const otherError = new Error('something wrong');
7068
- meeting.meetingRequest.getLocusStatusByUrl.rejects(otherError);
7069
- meeting.locusInfo.clearMainSessionLocusCache = sinon.stub();
7070
- await meeting.locusInfo.emit(
7071
- {function: 'test', file: 'test'},
7072
- 'CONTROLS_JOIN_BREAKOUT_FROM_MAIN',
7073
- {mainLocusUrl}
7074
- );
7075
-
7076
- assert.notCalled(meeting.locusInfo.clearMainSessionLocusCache);
7077
- });
7078
-
7079
7455
  it('listens to the locus interpretation update event', () => {
7080
7456
  const interpretation = {
7081
7457
  siLanguages: [{languageCode: 20, languageName: 'en'}],
@@ -7203,8 +7579,8 @@ describe('plugin-meetings', () => {
7203
7579
  newLocusServices.services.webcast.url
7204
7580
  );
7205
7581
  assert.calledWith(
7206
- meeting.webinar.webinarAttendeesSearchingUrlUpdate,
7207
- newLocusServices.services.webinarAttendeesSearching.url
7582
+ meeting.webinar.webinarAttendeesSearchingUrlUpdate,
7583
+ newLocusServices.services.webinarAttendeesSearching.url
7208
7584
  );
7209
7585
  assert.calledOnce(meeting.recordingController.setSessionId);
7210
7586
  done();
@@ -7380,20 +7756,19 @@ describe('plugin-meetings', () => {
7380
7756
  });
7381
7757
 
7382
7758
  describe('#setPermissionTokenPayload', () => {
7383
-
7384
7759
  let now;
7385
7760
  let clock;
7386
-
7761
+
7387
7762
  beforeEach(() => {
7388
7763
  now = Date.now();
7389
-
7764
+
7390
7765
  // mock `new Date()` with constant `now`
7391
7766
  clock = sinon.useFakeTimers(now);
7392
7767
  });
7393
-
7768
+
7394
7769
  afterEach(() => {
7395
7770
  clock.restore();
7396
- })
7771
+ });
7397
7772
  it('sets correctly', () => {
7398
7773
  assert.notOk(meeting.permissionTokenPayload);
7399
7774
 
@@ -7415,10 +7790,12 @@ describe('plugin-meetings', () => {
7415
7790
 
7416
7791
  const testUrl = 'https://example.com';
7417
7792
 
7418
- const policyData = {permission: {
7419
- userPolicies: {a: true},
7420
- enforceVBGImagesURL: testUrl
7421
- }};
7793
+ const policyData = {
7794
+ permission: {
7795
+ userPolicies: {a: true},
7796
+ enforceVBGImagesURL: testUrl,
7797
+ },
7798
+ };
7422
7799
  meeting.permissionTokenPayload = policyData;
7423
7800
 
7424
7801
  meeting.setSelfUserPolicies();
@@ -7519,8 +7896,11 @@ describe('plugin-meetings', () => {
7519
7896
  assert.equal(meeting.permissionToken, expectedInfoToParse.permissionToken);
7520
7897
  assert.deepEqual(meeting.selfUserPolicies, expectedInfoToParse.selfUserPolicies);
7521
7898
 
7522
- if(expectedInfoToParse.permissionTokenPayload) {
7523
- assert.deepEqual(meeting.permissionTokenPayload, expectedInfoToParse.permissionTokenPayload);
7899
+ if (expectedInfoToParse.permissionTokenPayload) {
7900
+ assert.deepEqual(
7901
+ meeting.permissionTokenPayload,
7902
+ expectedInfoToParse.permissionTokenPayload
7903
+ );
7524
7904
  }
7525
7905
  };
7526
7906
 
@@ -7529,12 +7909,12 @@ describe('plugin-meetings', () => {
7529
7909
  meeting.config.experimental.enableUnifiedMeetings = true;
7530
7910
 
7531
7911
  const expectedPermissionTokenPayload = {
7532
- exp: "123456",
7912
+ exp: '123456',
7533
7913
  permission: {
7534
7914
  userPolicies: {
7535
- a: true
7536
- }
7537
- }
7915
+ a: true,
7916
+ },
7917
+ },
7538
7918
  };
7539
7919
 
7540
7920
  // generated permissionToken with secret `secret` and
@@ -7543,16 +7923,14 @@ describe('plugin-meetings', () => {
7543
7923
  'eyJhbGciOiJIUzI1NiJ9.eyJleHAiOiIxMjM0NTYiLCJwZXJtaXNzaW9uIjp7InVzZXJQb2xpY2llcyI6eyJhIjp0cnVlfX19.wkTk0Hp8sUlq2wi2nP4-Ym4Xb7aEUHzyXA1kzk6f0V0';
7544
7924
 
7545
7925
  const FAKE_MEETING_INFO = {
7546
- body: {
7547
- conversationUrl: uuid1,
7548
- locusUrl: url1,
7549
- meetingJoinUrl: url2,
7550
- meetingNumber: '12345',
7551
- permissionToken,
7552
- sipMeetingUri: test1,
7553
- sipUrl: test1,
7554
- owner: test2,
7555
- },
7926
+ conversationUrl: uuid1,
7927
+ locusUrl: url1,
7928
+ meetingJoinUrl: url2,
7929
+ meetingNumber: '12345',
7930
+ permissionToken,
7931
+ sipMeetingUri: test1,
7932
+ sipUrl: test1,
7933
+ owner: test2,
7556
7934
  };
7557
7935
 
7558
7936
  meeting.parseMeetingInfo(FAKE_MEETING_INFO);
@@ -7566,7 +7944,7 @@ describe('plugin-meetings', () => {
7566
7944
  owner: test2,
7567
7945
  selfUserPolicies: {a: true},
7568
7946
  permissionToken,
7569
- permissionTokenPayload: expectedPermissionTokenPayload
7947
+ permissionTokenPayload: expectedPermissionTokenPayload,
7570
7948
  };
7571
7949
 
7572
7950
  checkParseMeetingInfo(expectedInfoToParse);
@@ -7584,16 +7962,14 @@ describe('plugin-meetings', () => {
7584
7962
  },
7585
7963
  };
7586
7964
  const FAKE_MEETING_INFO = {
7587
- body: {
7588
- conversationUrl: uuid1,
7589
- locusUrl: url1,
7590
- meetingJoinUrl: url2,
7591
- meetingNumber: '12345',
7592
- permissionToken: 'abc',
7593
- sipMeetingUri: test1,
7594
- sipUrl: test1,
7595
- owner: test2,
7596
- },
7965
+ conversationUrl: uuid1,
7966
+ locusUrl: url1,
7967
+ meetingJoinUrl: url2,
7968
+ meetingNumber: '12345',
7969
+ permissionToken: 'abc',
7970
+ sipMeetingUri: test1,
7971
+ sipUrl: test1,
7972
+ owner: test2,
7597
7973
  };
7598
7974
 
7599
7975
  meeting.parseMeetingInfo(FAKE_MEETING_INFO, FAKE_LOCUS_MEETING);
@@ -7613,16 +7989,14 @@ describe('plugin-meetings', () => {
7613
7989
  meeting.config.experimental = {enableMediaNegotiatedEvent: true};
7614
7990
  meeting.config.experimental.enableUnifiedMeetings = true;
7615
7991
  const FAKE_MEETING_INFO = {
7616
- body: {
7617
- conversationUrl: uuid1,
7618
- locusUrl: url1,
7619
- meetingJoinUrl: url2,
7620
- meetingNumber: '12345',
7621
- permissionToken: 'abc',
7622
- sipMeetingUri: test1,
7623
- sipUrl: test1,
7624
- owner: test2,
7625
- },
7992
+ conversationUrl: uuid1,
7993
+ locusUrl: url1,
7994
+ meetingJoinUrl: url2,
7995
+ meetingNumber: '12345',
7996
+ permissionToken: 'abc',
7997
+ sipMeetingUri: test1,
7998
+ sipUrl: test1,
7999
+ owner: test2,
7626
8000
  };
7627
8001
 
7628
8002
  meeting.parseMeetingInfo(FAKE_MEETING_INFO);
@@ -7643,16 +8017,14 @@ describe('plugin-meetings', () => {
7643
8017
  meeting.config.experimental.enableUnifiedMeetings = true;
7644
8018
  const FAKE_STRING_DESTINATION = 'sipUrl';
7645
8019
  const FAKE_MEETING_INFO = {
7646
- body: {
7647
- conversationUrl: uuid1,
7648
- locusUrl: url1,
7649
- meetingJoinUrl: url2,
7650
- meetingNumber: '12345',
7651
- permissionToken: 'abc',
7652
- sipMeetingUri: test1,
7653
- sipUrl: test1,
7654
- owner: test2,
7655
- },
8020
+ conversationUrl: uuid1,
8021
+ locusUrl: url1,
8022
+ meetingJoinUrl: url2,
8023
+ meetingNumber: '12345',
8024
+ permissionToken: 'abc',
8025
+ sipMeetingUri: test1,
8026
+ sipUrl: test1,
8027
+ owner: test2,
7656
8028
  };
7657
8029
 
7658
8030
  meeting.parseMeetingInfo(FAKE_MEETING_INFO, FAKE_STRING_DESTINATION);
@@ -7671,24 +8043,42 @@ describe('plugin-meetings', () => {
7671
8043
  it('should parse interpretation info correctly', () => {
7672
8044
  const parseInterpretationInfo = sinon.spy(MeetingUtil, 'parseInterpretationInfo');
7673
8045
  const mockToggleOnData = {
7674
- body: {
7675
- meetingSiteSetting: {
7676
- enableHostInterpreterControlSI: true,
7677
- },
7678
- turnOnSimultaneousInterpretation: true,
7679
- simultaneousInterpretation: {
7680
- currentSIInterpreter: false,
7681
- siLanguages: [
7682
- {
7683
- languageCode: 'ar',
7684
- languageGroupId: 4,
7685
- },
7686
- ],
7687
- },
8046
+ meetingSiteSetting: {
8047
+ enableHostInterpreterControlSI: true,
8048
+ },
8049
+ turnOnSimultaneousInterpretation: true,
8050
+ simultaneousInterpretation: {
8051
+ currentSIInterpreter: false,
8052
+ siLanguages: [
8053
+ {
8054
+ languageCode: 'ar',
8055
+ languageGroupId: 4,
8056
+ },
8057
+ ],
7688
8058
  },
7689
8059
  };
7690
8060
  meeting.parseMeetingInfo(mockToggleOnData);
7691
- assert.calledOnceWithExactly(parseInterpretationInfo, meeting, mockToggleOnData.body);
8061
+ assert.calledOnceWithExactly(parseInterpretationInfo, meeting, mockToggleOnData);
8062
+ });
8063
+
8064
+ it('should handle error', () => {
8065
+ const parseInterpretationInfo = sinon.spy(MeetingUtil, 'parseInterpretationInfo');
8066
+ const FAKE_MEETING_INFO = {
8067
+ conversationUrl: uuid1,
8068
+ locusUrl: url1,
8069
+ meetingJoinUrl: url2,
8070
+ meetingNumber: '12345',
8071
+ permissionToken: 'abc',
8072
+ sipMeetingUri: test1,
8073
+ sipUrl: test1,
8074
+ owner: test2,
8075
+ };
8076
+ meeting.parseMeetingInfo(FAKE_MEETING_INFO, undefined, 'Error');
8077
+
8078
+ checkParseMeetingInfo({
8079
+ locusUrl: meeting.locusUrl,
8080
+ });
8081
+ assert.calledOnceWithExactly(parseInterpretationInfo, meeting, FAKE_MEETING_INFO);
7692
8082
  });
7693
8083
  });
7694
8084
 
@@ -9326,6 +9716,13 @@ describe('plugin-meetings', () => {
9326
9716
  assert.exists(whiteboardShare.then);
9327
9717
  await whiteboardShare;
9328
9718
  assert.calledOnce(meeting.meetingRequest.changeMeetingFloor);
9719
+
9720
+ // ensure the CA share metric is submitted
9721
+ assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
9722
+ name: 'client.share.initiated',
9723
+ payload: {mediaType: 'whiteboard'},
9724
+ options: {meetingId: meeting.id},
9725
+ });
9329
9726
  });
9330
9727
  });
9331
9728
  describe('#stopWhiteboardShare', () => {
@@ -9425,7 +9822,6 @@ describe('plugin-meetings', () => {
9425
9822
  REMOTE_B: 'remote-user-B-url',
9426
9823
  };
9427
9824
 
9428
-
9429
9825
  const generateContent = (
9430
9826
  beneficiaryId = null,
9431
9827
  disposition = null,
@@ -9434,7 +9830,7 @@ describe('plugin-meetings', () => {
9434
9830
  ) => ({
9435
9831
  beneficiaryId,
9436
9832
  disposition,
9437
- deviceUrlSharing
9833
+ deviceUrlSharing,
9438
9834
  });
9439
9835
  const generateWhiteboard = (
9440
9836
  beneficiaryId = null,
@@ -9453,7 +9849,7 @@ describe('plugin-meetings', () => {
9453
9849
  annotation,
9454
9850
  url,
9455
9851
  shareInstanceId,
9456
- deviceUrlSharing,
9852
+ deviceUrlSharing
9457
9853
  ) => {
9458
9854
  const newPayload = cloneDeep(payload);
9459
9855
 
@@ -9898,7 +10294,7 @@ describe('plugin-meetings', () => {
9898
10294
  true,
9899
10295
  false,
9900
10296
  USER_IDS.ME,
9901
- RESOURCE_URLS.WHITEBOARD_A,
10297
+ RESOURCE_URLS.WHITEBOARD_A
9902
10298
  );
9903
10299
  const data2 = generateData(
9904
10300
  data1.payload,
@@ -9907,7 +10303,7 @@ describe('plugin-meetings', () => {
9907
10303
  USER_IDS.ME,
9908
10304
  RESOURCE_URLS.WHITEBOARD_A,
9909
10305
  true,
9910
- USER_IDS.ME,
10306
+ USER_IDS.ME
9911
10307
  );
9912
10308
  const data3 = generateData(
9913
10309
  data2.payload,
@@ -9920,9 +10316,21 @@ describe('plugin-meetings', () => {
9920
10316
  undefined,
9921
10317
  undefined,
9922
10318
  undefined,
9923
- DEVICE_URL.LOCAL_WEB,
10319
+ DEVICE_URL.LOCAL_WEB
10320
+ );
10321
+ const data4 = generateData(
10322
+ data3.payload,
10323
+ false,
10324
+ true,
10325
+ USER_IDS.ME,
10326
+ undefined,
10327
+ undefined,
10328
+ undefined,
10329
+ undefined,
10330
+ undefined,
10331
+ undefined,
10332
+ DEVICE_URL.LOCAL_WEB
9924
10333
  );
9925
- const data4 = generateData(data3.payload, false, true, USER_IDS.ME, undefined, undefined, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
9926
10334
 
9927
10335
  payloadTestHelper([data1, data2, data3, data4]);
9928
10336
  });
@@ -9955,7 +10363,7 @@ describe('plugin-meetings', () => {
9955
10363
  undefined,
9956
10364
  undefined,
9957
10365
  undefined,
9958
- DEVICE_URL.REMOTE_A,
10366
+ DEVICE_URL.REMOTE_A
9959
10367
  );
9960
10368
  const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_A);
9961
10369
 
@@ -9990,9 +10398,21 @@ describe('plugin-meetings', () => {
9990
10398
  undefined,
9991
10399
  undefined,
9992
10400
  undefined,
9993
- DEVICE_URL.LOCAL_WEB,
10401
+ DEVICE_URL.LOCAL_WEB
10402
+ );
10403
+ const data4 = generateData(
10404
+ data3.payload,
10405
+ false,
10406
+ true,
10407
+ USER_IDS.ME,
10408
+ undefined,
10409
+ undefined,
10410
+ undefined,
10411
+ undefined,
10412
+ undefined,
10413
+ undefined,
10414
+ DEVICE_URL.LOCAL_WEB
9994
10415
  );
9995
- const data4 = generateData(data3.payload, false, true, USER_IDS.ME, undefined, undefined, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
9996
10416
 
9997
10417
  payloadTestHelper([data1, data2, data3, data4]);
9998
10418
  });
@@ -10025,7 +10445,7 @@ describe('plugin-meetings', () => {
10025
10445
  undefined,
10026
10446
  undefined,
10027
10447
  undefined,
10028
- DEVICE_URL.REMOTE_A,
10448
+ DEVICE_URL.REMOTE_A
10029
10449
  );
10030
10450
  const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_A);
10031
10451
 
@@ -10060,7 +10480,7 @@ describe('plugin-meetings', () => {
10060
10480
  undefined,
10061
10481
  undefined,
10062
10482
  undefined,
10063
- DEVICE_URL.REMOTE_B,
10483
+ DEVICE_URL.REMOTE_B
10064
10484
  );
10065
10485
  const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_B);
10066
10486
 
@@ -10070,7 +10490,19 @@ describe('plugin-meetings', () => {
10070
10490
 
10071
10491
  describe('Desktop --> Whiteboard A', () => {
10072
10492
  it('Scenario #1: you share desktop and then share whiteboard', () => {
10073
- const data1 = generateData(blankPayload, true, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
10493
+ const data1 = generateData(
10494
+ blankPayload,
10495
+ true,
10496
+ true,
10497
+ USER_IDS.ME,
10498
+ undefined,
10499
+ false,
10500
+ undefined,
10501
+ undefined,
10502
+ undefined,
10503
+ undefined,
10504
+ DEVICE_URL.LOCAL_WEB
10505
+ );
10074
10506
  const data2 = generateData(
10075
10507
  data1.payload,
10076
10508
  true,
@@ -10084,7 +10516,19 @@ describe('plugin-meetings', () => {
10084
10516
  });
10085
10517
 
10086
10518
  it('Scenario #2: you share desktop and remote person A shares whiteboard', () => {
10087
- const data1 = generateData(blankPayload, true, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
10519
+ const data1 = generateData(
10520
+ blankPayload,
10521
+ true,
10522
+ true,
10523
+ USER_IDS.ME,
10524
+ undefined,
10525
+ false,
10526
+ undefined,
10527
+ undefined,
10528
+ undefined,
10529
+ undefined,
10530
+ DEVICE_URL.LOCAL_WEB
10531
+ );
10088
10532
  const data2 = generateData(
10089
10533
  data1.payload,
10090
10534
  true,
@@ -10098,7 +10542,19 @@ describe('plugin-meetings', () => {
10098
10542
  });
10099
10543
 
10100
10544
  it('Scenario #3: remote person A shares desktop and you share whiteboard', () => {
10101
- const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.REMOTE_A);
10545
+ const data1 = generateData(
10546
+ blankPayload,
10547
+ true,
10548
+ true,
10549
+ USER_IDS.REMOTE_A,
10550
+ undefined,
10551
+ false,
10552
+ undefined,
10553
+ undefined,
10554
+ undefined,
10555
+ undefined,
10556
+ DEVICE_URL.REMOTE_A
10557
+ );
10102
10558
  const data2 = generateData(
10103
10559
  data1.payload,
10104
10560
  true,
@@ -10112,7 +10568,19 @@ describe('plugin-meetings', () => {
10112
10568
  });
10113
10569
 
10114
10570
  it('Scenario #4: remote person A shares desktop and then shares whiteboard', () => {
10115
- const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.REMOTE_A);
10571
+ const data1 = generateData(
10572
+ blankPayload,
10573
+ true,
10574
+ true,
10575
+ USER_IDS.REMOTE_A,
10576
+ undefined,
10577
+ false,
10578
+ undefined,
10579
+ undefined,
10580
+ undefined,
10581
+ undefined,
10582
+ DEVICE_URL.REMOTE_A
10583
+ );
10116
10584
  const data2 = generateData(
10117
10585
  data1.payload,
10118
10586
  true,
@@ -10126,7 +10594,19 @@ describe('plugin-meetings', () => {
10126
10594
  });
10127
10595
 
10128
10596
  it('Scenario #5: remote person A shares desktop and remote person B shares whiteboard', () => {
10129
- const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.REMOTE_A);
10597
+ const data1 = generateData(
10598
+ blankPayload,
10599
+ true,
10600
+ true,
10601
+ USER_IDS.REMOTE_A,
10602
+ undefined,
10603
+ false,
10604
+ undefined,
10605
+ undefined,
10606
+ undefined,
10607
+ undefined,
10608
+ DEVICE_URL.REMOTE_A
10609
+ );
10130
10610
  const data2 = generateData(
10131
10611
  data1.payload,
10132
10612
  true,
@@ -10141,26 +10621,146 @@ describe('plugin-meetings', () => {
10141
10621
  });
10142
10622
  describe('Desktop A --> Desktop B', () => {
10143
10623
  it('Scenario #1: you share desktop using web client and then share using native client', () => {
10144
- const data1 = generateData(blankPayload, true, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
10145
- const data2 = generateData(data1.payload, false, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
10146
- const data3 = generateData(data2.payload, true, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_MAC);
10147
- const data4 = generateData(data3.payload, false, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_MAC);
10624
+ const data1 = generateData(
10625
+ blankPayload,
10626
+ true,
10627
+ true,
10628
+ USER_IDS.ME,
10629
+ undefined,
10630
+ false,
10631
+ undefined,
10632
+ undefined,
10633
+ undefined,
10634
+ undefined,
10635
+ DEVICE_URL.LOCAL_WEB
10636
+ );
10637
+ const data2 = generateData(
10638
+ data1.payload,
10639
+ false,
10640
+ true,
10641
+ USER_IDS.ME,
10642
+ undefined,
10643
+ false,
10644
+ undefined,
10645
+ undefined,
10646
+ undefined,
10647
+ undefined,
10648
+ DEVICE_URL.LOCAL_WEB
10649
+ );
10650
+ const data3 = generateData(
10651
+ data2.payload,
10652
+ true,
10653
+ true,
10654
+ USER_IDS.ME,
10655
+ undefined,
10656
+ false,
10657
+ undefined,
10658
+ undefined,
10659
+ undefined,
10660
+ undefined,
10661
+ DEVICE_URL.LOCAL_MAC
10662
+ );
10663
+ const data4 = generateData(
10664
+ data3.payload,
10665
+ false,
10666
+ true,
10667
+ USER_IDS.ME,
10668
+ undefined,
10669
+ false,
10670
+ undefined,
10671
+ undefined,
10672
+ undefined,
10673
+ undefined,
10674
+ DEVICE_URL.LOCAL_MAC
10675
+ );
10148
10676
 
10149
10677
  payloadTestHelper([data1, data2, data3, data4]);
10150
10678
  });
10151
10679
 
10152
10680
  it('Scenario #2: you share desktop using web client and remote person A shares desktop', () => {
10153
- const data1 = generateData(blankPayload, true, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
10154
- const data2 = generateData(data1.payload, true, true, USER_IDS.REMOTE_A, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.REMOTE_A) ;
10155
- const data3 = generateData(data2.payload, false, true, USER_IDS.REMOTE_A, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.REMOTE_A);
10681
+ const data1 = generateData(
10682
+ blankPayload,
10683
+ true,
10684
+ true,
10685
+ USER_IDS.ME,
10686
+ undefined,
10687
+ false,
10688
+ undefined,
10689
+ undefined,
10690
+ undefined,
10691
+ undefined,
10692
+ DEVICE_URL.LOCAL_WEB
10693
+ );
10694
+ const data2 = generateData(
10695
+ data1.payload,
10696
+ true,
10697
+ true,
10698
+ USER_IDS.REMOTE_A,
10699
+ undefined,
10700
+ false,
10701
+ undefined,
10702
+ undefined,
10703
+ undefined,
10704
+ undefined,
10705
+ DEVICE_URL.REMOTE_A
10706
+ );
10707
+ const data3 = generateData(
10708
+ data2.payload,
10709
+ false,
10710
+ true,
10711
+ USER_IDS.REMOTE_A,
10712
+ undefined,
10713
+ false,
10714
+ undefined,
10715
+ undefined,
10716
+ undefined,
10717
+ undefined,
10718
+ DEVICE_URL.REMOTE_A
10719
+ );
10156
10720
 
10157
10721
  payloadTestHelper([data1, data2, data3]);
10158
10722
  });
10159
10723
 
10160
10724
  it('Scenario #3: remote person A shares desktop and then you share desktop using web client', () => {
10161
- const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.REMOTE_A);
10162
- const data2 = generateData(data1.payload, true, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
10163
- const data3 = generateData(data2.payload, false, true, USER_IDS.ME, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
10725
+ const data1 = generateData(
10726
+ blankPayload,
10727
+ true,
10728
+ true,
10729
+ USER_IDS.REMOTE_A,
10730
+ undefined,
10731
+ false,
10732
+ undefined,
10733
+ undefined,
10734
+ undefined,
10735
+ undefined,
10736
+ DEVICE_URL.REMOTE_A
10737
+ );
10738
+ const data2 = generateData(
10739
+ data1.payload,
10740
+ true,
10741
+ true,
10742
+ USER_IDS.ME,
10743
+ undefined,
10744
+ false,
10745
+ undefined,
10746
+ undefined,
10747
+ undefined,
10748
+ undefined,
10749
+ DEVICE_URL.LOCAL_WEB
10750
+ );
10751
+ const data3 = generateData(
10752
+ data2.payload,
10753
+ false,
10754
+ true,
10755
+ USER_IDS.ME,
10756
+ undefined,
10757
+ false,
10758
+ undefined,
10759
+ undefined,
10760
+ undefined,
10761
+ undefined,
10762
+ DEVICE_URL.LOCAL_WEB
10763
+ );
10164
10764
 
10165
10765
  payloadTestHelper([data1, data2, data3]);
10166
10766
  });
@@ -10174,8 +10774,32 @@ describe('plugin-meetings', () => {
10174
10774
  });
10175
10775
 
10176
10776
  it('Scenario #5: remote person A shares desktop A and remote person B shares desktop B', () => {
10177
- const data1 = generateData(blankPayload, true, true, USER_IDS.REMOTE_A, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.REMOTE_A);
10178
- const data2 = generateData(data1.payload, true, true, USER_IDS.REMOTE_B, undefined, false, undefined, undefined, undefined, undefined, DEVICE_URL.REMOTE_B);
10777
+ const data1 = generateData(
10778
+ blankPayload,
10779
+ true,
10780
+ true,
10781
+ USER_IDS.REMOTE_A,
10782
+ undefined,
10783
+ false,
10784
+ undefined,
10785
+ undefined,
10786
+ undefined,
10787
+ undefined,
10788
+ DEVICE_URL.REMOTE_A
10789
+ );
10790
+ const data2 = generateData(
10791
+ data1.payload,
10792
+ true,
10793
+ true,
10794
+ USER_IDS.REMOTE_B,
10795
+ undefined,
10796
+ false,
10797
+ undefined,
10798
+ undefined,
10799
+ undefined,
10800
+ undefined,
10801
+ DEVICE_URL.REMOTE_B
10802
+ );
10179
10803
  const data3 = generateData(data2.payload, false, true, USER_IDS.REMOTE_B);
10180
10804
 
10181
10805
  payloadTestHelper([data1, data2, data3]);
@@ -10594,26 +11218,34 @@ describe('plugin-meetings', () => {
10594
11218
 
10595
11219
  afterEach(() => {
10596
11220
  clock.restore();
10597
- })
11221
+ });
10598
11222
 
10599
11223
  it('should return undefined if exp is undefined', () => {
10600
- assert.equal(meeting.getPermissionTokenExpiryInfo(), undefined)
11224
+ assert.equal(meeting.getPermissionTokenExpiryInfo(), undefined);
10601
11225
  });
10602
11226
 
10603
11227
  it('should return the expected positive exp', () => {
10604
11228
  // set permission token as now + 1 sec
10605
11229
  const expiryTime = now + 1000;
10606
- meeting.permissionTokenPayload = {exp: (expiryTime).toString(), iat: now};
11230
+ meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: now};
10607
11231
  meeting.permissionTokenReceivedLocalTime = now;
10608
- assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {timeLeft: 1, expiryTime: Number(expiryTime), currentTime: now});
11232
+ assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
11233
+ timeLeft: 1,
11234
+ expiryTime: Number(expiryTime),
11235
+ currentTime: now,
11236
+ });
10609
11237
  });
10610
11238
 
10611
11239
  it('should return the expected negative exp', () => {
10612
11240
  // set permission token as now - 1 sec
10613
11241
  const expiryTime = now - 1000;
10614
- meeting.permissionTokenPayload = {exp: (expiryTime).toString(), iat: now};
11242
+ meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: now};
10615
11243
  meeting.permissionTokenReceivedLocalTime = now;
10616
- assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {timeLeft: -1, expiryTime: Number(expiryTime), currentTime: now});
11244
+ assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
11245
+ timeLeft: -1,
11246
+ expiryTime: Number(expiryTime),
11247
+ currentTime: now,
11248
+ });
10617
11249
  });
10618
11250
 
10619
11251
  describe('#getPermissionTokenExpiryInfo with wrong current time which is in future', () => {
@@ -10622,34 +11254,41 @@ describe('plugin-meetings', () => {
10622
11254
  beforeEach(() => {
10623
11255
  // current time is 3 hours off
10624
11256
  now = Date.now() + 10800000;
10625
-
11257
+
10626
11258
  // mock `new Date()` with constant `now`
10627
11259
  clock = sinon.useFakeTimers(now);
10628
11260
  });
10629
-
11261
+
10630
11262
  afterEach(() => {
10631
11263
  clock.restore();
10632
- })
10633
-
11264
+ });
11265
+
10634
11266
  it('should return the expected positive exp when client time is wrong', () => {
10635
11267
  const serverTime = Date.now();
10636
-
10637
- // set permission token as now + 1 sec
11268
+
11269
+ // set permission token as now + 1 sec
10638
11270
  const expiryTime = serverTime + 1000;
10639
- meeting.permissionTokenPayload = {exp: (expiryTime).toString(), iat: serverTime};
11271
+ meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: serverTime};
10640
11272
  meeting.permissionTokenReceivedLocalTime = now;
10641
- assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {timeLeft: 1, expiryTime: Number(expiryTime), currentTime: now});
11273
+ assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
11274
+ timeLeft: 1,
11275
+ expiryTime: Number(expiryTime),
11276
+ currentTime: now,
11277
+ });
10642
11278
  });
10643
-
11279
+
10644
11280
  it('should return the expected negative exp when client time is wrong', () => {
10645
11281
  const serverTime = Date.now();
10646
11282
  // set permission token as now - 1 sec
10647
11283
  const expiryTime = serverTime - 1000;
10648
- meeting.permissionTokenPayload = {exp: (expiryTime).toString(), iat: serverTime};
11284
+ meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: serverTime};
10649
11285
  meeting.permissionTokenReceivedLocalTime = now;
10650
- assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {timeLeft: -1, expiryTime: Number(expiryTime), currentTime: now});
11286
+ assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
11287
+ timeLeft: -1,
11288
+ expiryTime: Number(expiryTime),
11289
+ currentTime: now,
11290
+ });
10651
11291
  });
10652
-
10653
11292
  });
10654
11293
 
10655
11294
  describe('#getPermissionTokenExpiryInfo with wrong current Time which is in the past', () => {
@@ -10658,42 +11297,47 @@ describe('plugin-meetings', () => {
10658
11297
  beforeEach(() => {
10659
11298
  // current time is 3 hours off
10660
11299
  now = Date.now() - 10800000;
10661
-
11300
+
10662
11301
  // mock `new Date()` with constant `now`
10663
11302
  clock = sinon.useFakeTimers(now);
10664
11303
  });
10665
-
11304
+
10666
11305
  afterEach(() => {
10667
11306
  clock.restore();
10668
- })
10669
-
11307
+ });
11308
+
10670
11309
  it('should return the expected positive exp when client time is wrong', () => {
10671
11310
  const serverTime = Date.now();
10672
-
10673
- // set permission token as now + 1 sec
11311
+
11312
+ // set permission token as now + 1 sec
10674
11313
  const expiryTime = serverTime + 1000;
10675
- meeting.permissionTokenPayload = {exp: (expiryTime).toString(), iat: serverTime};
11314
+ meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: serverTime};
10676
11315
  meeting.permissionTokenReceivedLocalTime = now;
10677
- assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {timeLeft: 1, expiryTime: Number(expiryTime), currentTime: now});
11316
+ assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
11317
+ timeLeft: 1,
11318
+ expiryTime: Number(expiryTime),
11319
+ currentTime: now,
11320
+ });
10678
11321
  });
10679
-
11322
+
10680
11323
  it('should return the expected negative exp when client time is wrong', () => {
10681
11324
  const serverTime = Date.now();
10682
11325
  // set permission token as now - 1 sec
10683
11326
  const expiryTime = serverTime - 1000;
10684
- meeting.permissionTokenPayload = {exp: (expiryTime).toString(), iat: serverTime};
11327
+ meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: serverTime};
10685
11328
  meeting.permissionTokenReceivedLocalTime = now;
10686
- assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {timeLeft: -1, expiryTime: Number(expiryTime), currentTime: now});
11329
+ assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
11330
+ timeLeft: -1,
11331
+ expiryTime: Number(expiryTime),
11332
+ currentTime: now,
11333
+ });
10687
11334
  });
10688
-
10689
11335
  });
10690
11336
  });
10691
11337
 
10692
-
10693
-
10694
11338
  describe('#checkAndRefreshPermissionToken', () => {
10695
- it('should not fire refreshPermissionToken if permissionToken is not defined', async() => {
10696
- meeting.getPermissionTokenExpiryInfo = sinon.stub().returns(undefined)
11339
+ it('should not fire refreshPermissionToken if permissionToken is not defined', async () => {
11340
+ meeting.getPermissionTokenExpiryInfo = sinon.stub().returns(undefined);
10697
11341
  meeting.refreshPermissionToken = sinon.stub().returns(Promise.resolve('test return value'));
10698
11342
 
10699
11343
  const returnValue = await meeting.checkAndRefreshPermissionToken(10, 'ttl-join');
@@ -10703,8 +11347,10 @@ describe('plugin-meetings', () => {
10703
11347
  assert.equal(returnValue, undefined);
10704
11348
  });
10705
11349
 
10706
- it('should fire refreshPermissionToken if time left is below 10sec', async() => {
10707
- meeting.getPermissionTokenExpiryInfo = sinon.stub().returns({timeLeft: 9, expiryTime: 122132, currentTime: Date.now()})
11350
+ it('should fire refreshPermissionToken if time left is below 10sec', async () => {
11351
+ meeting.getPermissionTokenExpiryInfo = sinon
11352
+ .stub()
11353
+ .returns({timeLeft: 9, expiryTime: 122132, currentTime: Date.now()});
10708
11354
  meeting.refreshPermissionToken = sinon.stub().returns(Promise.resolve('test return value'));
10709
11355
 
10710
11356
  const returnValue = await meeting.checkAndRefreshPermissionToken(10, 'ttl-join');
@@ -10715,7 +11361,9 @@ describe('plugin-meetings', () => {
10715
11361
  });
10716
11362
 
10717
11363
  it('should fire refreshPermissionToken if time left is equal 10sec', async () => {
10718
- meeting.getPermissionTokenExpiryInfo = sinon.stub().returns({timeLeft: 10, expiryTime: 122132, currentTime: Date.now()})
11364
+ meeting.getPermissionTokenExpiryInfo = sinon
11365
+ .stub()
11366
+ .returns({timeLeft: 10, expiryTime: 122132, currentTime: Date.now()});
10719
11367
  meeting.refreshPermissionToken = sinon.stub().returns(Promise.resolve('test return value'));
10720
11368
 
10721
11369
  const returnValue = await meeting.checkAndRefreshPermissionToken(10, 'ttl-join');
@@ -10726,7 +11374,9 @@ describe('plugin-meetings', () => {
10726
11374
  });
10727
11375
 
10728
11376
  it('should not fire refreshPermissionToken if time left is higher than 10sec', async () => {
10729
- meeting.getPermissionTokenExpiryInfo = sinon.stub().returns({timeLeft: 11, expiryTime: 122132, currentTime: Date.now()})
11377
+ meeting.getPermissionTokenExpiryInfo = sinon
11378
+ .stub()
11379
+ .returns({timeLeft: 11, expiryTime: 122132, currentTime: Date.now()});
10730
11380
  meeting.refreshPermissionToken = sinon.stub().returns(Promise.resolve('test return value'));
10731
11381
 
10732
11382
  const returnValue = await meeting.checkAndRefreshPermissionToken(10, 'ttl-join');
@@ -10739,19 +11389,22 @@ describe('plugin-meetings', () => {
10739
11389
 
10740
11390
  describe('#roapMessageReceived', () => {
10741
11391
  it('calls roapMessageReceived on the webrtc media connection', () => {
10742
- const fakeMessage = { messageType: 'fake', sdp: 'fake sdp'};
11392
+ const fakeMessage = {messageType: 'fake', sdp: 'fake sdp'};
10743
11393
 
10744
11394
  const getMediaServer = sinon.stub(MeetingsUtil, 'getMediaServer').returns('homer');
10745
11395
 
10746
11396
  meeting.mediaProperties.webrtcMediaConnection = {
10747
- roapMessageReceived: sinon.stub()
11397
+ roapMessageReceived: sinon.stub(),
10748
11398
  };
10749
11399
 
10750
11400
  meeting.roapMessageReceived(fakeMessage);
10751
11401
 
10752
- assert.calledOnceWithExactly(meeting.mediaProperties.webrtcMediaConnection.roapMessageReceived, fakeMessage);
11402
+ assert.calledOnceWithExactly(
11403
+ meeting.mediaProperties.webrtcMediaConnection.roapMessageReceived,
11404
+ fakeMessage
11405
+ );
10753
11406
  assert.calledOnceWithExactly(getMediaServer, 'fake sdp');
10754
11407
  assert.equal(meeting.mediaProperties.webrtcMediaConnection.mediaServer, 'homer');
10755
- })
10756
- })
11408
+ });
11409
+ });
10757
11410
  });