@webex/plugin-meetings 3.0.0-beta.351 → 3.0.0-beta.352
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/meeting/index.js +586 -522
- package/dist/meeting/index.js.map +1 -1
- package/dist/meetings/index.js +53 -29
- package/dist/meetings/index.js.map +1 -1
- package/dist/types/meeting/index.d.ts +60 -18
- package/dist/types/meetings/index.d.ts +12 -1
- package/dist/webinar/index.js +1 -1
- package/package.json +19 -19
- package/src/meeting/index.ts +142 -97
- package/src/meetings/index.ts +35 -14
- package/test/unit/spec/meeting/index.js +1695 -1052
- package/test/unit/spec/meetings/index.js +141 -20
|
@@ -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 {
|
|
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 {
|
|
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 {
|
|
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: {
|
|
867
|
+
payload: {
|
|
868
|
+
trigger: 'user-interaction',
|
|
869
|
+
isRoapCallEnabled: true,
|
|
870
|
+
pstnAudioType: 'dial-in',
|
|
871
|
+
},
|
|
872
872
|
options: {meetingId: meeting.id},
|
|
873
873
|
});
|
|
874
874
|
|
|
@@ -1034,22 +1034,23 @@ describe('plugin-meetings', () => {
|
|
|
1034
1034
|
|
|
1035
1035
|
assert.equal(result, joinMeetingResult);
|
|
1036
1036
|
|
|
1037
|
-
defer.reject(new Error(
|
|
1037
|
+
defer.reject(new Error('bad day', {cause: 'bad weather'}));
|
|
1038
1038
|
|
|
1039
1039
|
try {
|
|
1040
1040
|
await defer.promise;
|
|
1041
1041
|
} catch (err) {
|
|
1042
|
-
|
|
1043
1042
|
assert.deepEqual(Metrics.sendBehavioralMetric.getCalls()[0].args, [
|
|
1044
|
-
BEHAVIORAL_METRICS.JOIN_SUCCESS,
|
|
1045
|
-
|
|
1043
|
+
BEHAVIORAL_METRICS.JOIN_SUCCESS,
|
|
1044
|
+
{correlation_id: meeting.correlationId},
|
|
1045
|
+
]);
|
|
1046
1046
|
|
|
1047
1047
|
assert.deepEqual(Metrics.sendBehavioralMetric.getCalls()[1].args, [
|
|
1048
|
-
BEHAVIORAL_METRICS.LLM_CONNECTION_AFTER_JOIN_FAILURE,
|
|
1048
|
+
BEHAVIORAL_METRICS.LLM_CONNECTION_AFTER_JOIN_FAILURE,
|
|
1049
|
+
{
|
|
1049
1050
|
correlation_id: meeting.correlationId,
|
|
1050
1051
|
reason: err.message,
|
|
1051
1052
|
stack: err.stack,
|
|
1052
|
-
}
|
|
1053
|
+
},
|
|
1053
1054
|
]);
|
|
1054
1055
|
}
|
|
1055
1056
|
});
|
|
@@ -1087,25 +1088,27 @@ describe('plugin-meetings', () => {
|
|
|
1087
1088
|
|
|
1088
1089
|
assert.equal(result, joinMeetingResult);
|
|
1089
1090
|
|
|
1090
|
-
defer.reject(new Error(
|
|
1091
|
+
defer.reject(new Error('bad day', {cause: 'bad weather'}));
|
|
1091
1092
|
|
|
1092
1093
|
try {
|
|
1093
1094
|
await defer.promise;
|
|
1094
1095
|
} catch (err) {
|
|
1095
1096
|
assert.deepEqual(Metrics.sendBehavioralMetric.getCalls()[0].args, [
|
|
1096
|
-
BEHAVIORAL_METRICS.JOIN_SUCCESS,
|
|
1097
|
-
|
|
1097
|
+
BEHAVIORAL_METRICS.JOIN_SUCCESS,
|
|
1098
|
+
{correlation_id: meeting.correlationId},
|
|
1099
|
+
]);
|
|
1098
1100
|
|
|
1099
1101
|
assert.deepEqual(Metrics.sendBehavioralMetric.getCalls()[1].args, [
|
|
1100
|
-
BEHAVIORAL_METRICS.RECEIVE_TRANSCRIPTION_AFTER_JOIN_FAILURE,
|
|
1102
|
+
BEHAVIORAL_METRICS.RECEIVE_TRANSCRIPTION_AFTER_JOIN_FAILURE,
|
|
1103
|
+
{
|
|
1101
1104
|
correlation_id: meeting.correlationId,
|
|
1102
1105
|
reason: err.message,
|
|
1103
1106
|
stack: err.stack,
|
|
1104
|
-
}
|
|
1107
|
+
},
|
|
1105
1108
|
]);
|
|
1106
1109
|
}
|
|
1107
|
-
})
|
|
1108
|
-
})
|
|
1110
|
+
});
|
|
1111
|
+
});
|
|
1109
1112
|
|
|
1110
1113
|
describe('refreshPermissionToken', () => {
|
|
1111
1114
|
it('should continue if permissionTokenRefresh fails with a generic error', async () => {
|
|
@@ -1116,14 +1119,20 @@ describe('plugin-meetings', () => {
|
|
|
1116
1119
|
const result = await meeting.join();
|
|
1117
1120
|
assert.notCalled(stateMachineFailSpy);
|
|
1118
1121
|
assert.equal(result, joinMeetingResult);
|
|
1119
|
-
assert.calledOnceWithExactly(
|
|
1122
|
+
assert.calledOnceWithExactly(
|
|
1123
|
+
meeting.checkAndRefreshPermissionToken,
|
|
1124
|
+
30,
|
|
1125
|
+
'ttl-join'
|
|
1126
|
+
);
|
|
1120
1127
|
} catch (error) {
|
|
1121
1128
|
assert.fail('join should not throw an Error');
|
|
1122
1129
|
}
|
|
1123
|
-
})
|
|
1130
|
+
});
|
|
1124
1131
|
|
|
1125
1132
|
it('should throw if permissionTokenRefresh fails with a captcha error', async () => {
|
|
1126
|
-
meeting.checkAndRefreshPermissionToken = sinon
|
|
1133
|
+
meeting.checkAndRefreshPermissionToken = sinon
|
|
1134
|
+
.stub()
|
|
1135
|
+
.rejects(new CaptchaError('bad captcha'));
|
|
1127
1136
|
const stateMachineFailSpy = sinon.spy(meeting.meetingFiniteStateMachine, 'fail');
|
|
1128
1137
|
const joinMeetingOptionsSpy = sinon.spy(MeetingUtil, 'joinMeetingOptions');
|
|
1129
1138
|
|
|
@@ -1132,16 +1141,22 @@ describe('plugin-meetings', () => {
|
|
|
1132
1141
|
assert.fail('join should have thrown a Captcha Error.');
|
|
1133
1142
|
} catch (error) {
|
|
1134
1143
|
assert.calledOnce(stateMachineFailSpy);
|
|
1135
|
-
assert.calledOnceWithExactly(
|
|
1144
|
+
assert.calledOnceWithExactly(
|
|
1145
|
+
meeting.checkAndRefreshPermissionToken,
|
|
1146
|
+
30,
|
|
1147
|
+
'ttl-join'
|
|
1148
|
+
);
|
|
1136
1149
|
assert.instanceOf(error, CaptchaError);
|
|
1137
1150
|
assert.equal(error.message, 'bad captcha');
|
|
1138
1151
|
// should not get to the end promise chain, which does do the join
|
|
1139
1152
|
assert.notCalled(joinMeetingOptionsSpy);
|
|
1140
1153
|
}
|
|
1141
|
-
})
|
|
1154
|
+
});
|
|
1142
1155
|
|
|
1143
1156
|
it('should throw if permissionTokenRefresh fails with a password error', async () => {
|
|
1144
|
-
meeting.checkAndRefreshPermissionToken = sinon
|
|
1157
|
+
meeting.checkAndRefreshPermissionToken = sinon
|
|
1158
|
+
.stub()
|
|
1159
|
+
.rejects(new PasswordError('bad password'));
|
|
1145
1160
|
const stateMachineFailSpy = sinon.spy(meeting.meetingFiniteStateMachine, 'fail');
|
|
1146
1161
|
const joinMeetingOptionsSpy = sinon.spy(MeetingUtil.joinMeetingOptions);
|
|
1147
1162
|
|
|
@@ -1150,16 +1165,22 @@ describe('plugin-meetings', () => {
|
|
|
1150
1165
|
assert.fail('join should have thrown a Password Error.');
|
|
1151
1166
|
} catch (error) {
|
|
1152
1167
|
assert.calledOnce(stateMachineFailSpy);
|
|
1153
|
-
assert.calledOnceWithExactly(
|
|
1168
|
+
assert.calledOnceWithExactly(
|
|
1169
|
+
meeting.checkAndRefreshPermissionToken,
|
|
1170
|
+
30,
|
|
1171
|
+
'ttl-join'
|
|
1172
|
+
);
|
|
1154
1173
|
assert.instanceOf(error, PasswordError);
|
|
1155
1174
|
assert.equal(error.message, 'bad password');
|
|
1156
1175
|
// should not get to the end promise chain, which does do the join
|
|
1157
1176
|
assert.notCalled(joinMeetingOptionsSpy);
|
|
1158
1177
|
}
|
|
1159
|
-
})
|
|
1178
|
+
});
|
|
1160
1179
|
|
|
1161
1180
|
it('should throw if permissionTokenRefresh fails with a permission error', async () => {
|
|
1162
|
-
meeting.checkAndRefreshPermissionToken = sinon
|
|
1181
|
+
meeting.checkAndRefreshPermissionToken = sinon
|
|
1182
|
+
.stub()
|
|
1183
|
+
.rejects(new PermissionError('bad permission'));
|
|
1163
1184
|
const stateMachineFailSpy = sinon.spy(meeting.meetingFiniteStateMachine, 'fail');
|
|
1164
1185
|
const joinMeetingOptionsSpy = sinon.spy(MeetingUtil.joinMeetingOptions);
|
|
1165
1186
|
|
|
@@ -1168,15 +1189,19 @@ describe('plugin-meetings', () => {
|
|
|
1168
1189
|
assert.fail('join should have thrown a Permission Error.');
|
|
1169
1190
|
} catch (error) {
|
|
1170
1191
|
assert.calledOnce(stateMachineFailSpy);
|
|
1171
|
-
assert.calledOnceWithExactly(
|
|
1192
|
+
assert.calledOnceWithExactly(
|
|
1193
|
+
meeting.checkAndRefreshPermissionToken,
|
|
1194
|
+
30,
|
|
1195
|
+
'ttl-join'
|
|
1196
|
+
);
|
|
1172
1197
|
assert.instanceOf(error, PermissionError);
|
|
1173
1198
|
assert.equal(error.message, 'bad permission');
|
|
1174
1199
|
// should not get to the end promise chain, which does do the join
|
|
1175
1200
|
assert.notCalled(joinMeetingOptionsSpy);
|
|
1176
1201
|
}
|
|
1177
|
-
})
|
|
1178
|
-
})
|
|
1179
|
-
})
|
|
1202
|
+
});
|
|
1203
|
+
});
|
|
1204
|
+
});
|
|
1180
1205
|
});
|
|
1181
1206
|
|
|
1182
1207
|
describe('#addMedia', () => {
|
|
@@ -1246,7 +1271,7 @@ describe('plugin-meetings', () => {
|
|
|
1246
1271
|
meeting.webex.meetings.reachability = {
|
|
1247
1272
|
getReachabilityMetrics: sinon.stub().resolves({
|
|
1248
1273
|
someReachabilityMetric1: 'some value1',
|
|
1249
|
-
someReachabilityMetric2: 'some value2'
|
|
1274
|
+
someReachabilityMetric2: 'some value2',
|
|
1250
1275
|
}),
|
|
1251
1276
|
};
|
|
1252
1277
|
|
|
@@ -1706,9 +1731,9 @@ describe('plugin-meetings', () => {
|
|
|
1706
1731
|
|
|
1707
1732
|
it('should reject if waitForMediaConnectionConnected() rejects after turn server retry', async () => {
|
|
1708
1733
|
const FAKE_ERROR = {fatal: true};
|
|
1709
|
-
const getErrorPayloadForClientErrorCodeStub =
|
|
1710
|
-
.
|
|
1711
|
-
|
|
1734
|
+
const getErrorPayloadForClientErrorCodeStub =
|
|
1735
|
+
(webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode =
|
|
1736
|
+
sinon.stub().returns(FAKE_ERROR));
|
|
1712
1737
|
const MOCK_CLIENT_ERROR_CODE = 2004;
|
|
1713
1738
|
const generateClientErrorCodeForIceFailureStub = sinon
|
|
1714
1739
|
.stub(CallDiagnosticUtils, 'generateClientErrorCodeForIceFailure')
|
|
@@ -1719,17 +1744,22 @@ describe('plugin-meetings', () => {
|
|
|
1719
1744
|
let errorThrown = undefined;
|
|
1720
1745
|
|
|
1721
1746
|
// Stub doTurnDiscovery so that on the first call we skip turn discovery
|
|
1722
|
-
meeting.roap.doTurnDiscovery = sinon
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1747
|
+
meeting.roap.doTurnDiscovery = sinon
|
|
1748
|
+
.stub()
|
|
1749
|
+
.onFirstCall()
|
|
1750
|
+
.returns({
|
|
1751
|
+
turnServerInfo: undefined,
|
|
1752
|
+
turnDiscoverySkippedReason: 'reachability',
|
|
1753
|
+
})
|
|
1754
|
+
.onSecondCall()
|
|
1755
|
+
.returns({
|
|
1756
|
+
turnServerInfo: {
|
|
1757
|
+
url: FAKE_TURN_URL,
|
|
1758
|
+
username: FAKE_TURN_USER,
|
|
1759
|
+
password: FAKE_TURN_PASSWORD,
|
|
1760
|
+
},
|
|
1761
|
+
turnDiscoverySkippedReason: undefined,
|
|
1762
|
+
});
|
|
1733
1763
|
meeting.meetingState = 'ACTIVE';
|
|
1734
1764
|
meeting.mediaProperties.waitForMediaConnectionConnected.rejects(new Error('fake error'));
|
|
1735
1765
|
|
|
@@ -1757,18 +1787,20 @@ describe('plugin-meetings', () => {
|
|
|
1757
1787
|
signalingState: 'unknown',
|
|
1758
1788
|
iceConnectionState: 'unknown',
|
|
1759
1789
|
turnServerUsed: false,
|
|
1760
|
-
})
|
|
1790
|
+
});
|
|
1761
1791
|
assert.calledWith(generateClientErrorCodeForIceFailureStub, {
|
|
1762
1792
|
signalingState: 'unknown',
|
|
1763
1793
|
iceConnectionState: 'unknown',
|
|
1764
1794
|
turnServerUsed: true,
|
|
1765
|
-
})
|
|
1795
|
+
});
|
|
1766
1796
|
|
|
1767
1797
|
assert.calledTwice(getErrorPayloadForClientErrorCodeStub);
|
|
1768
|
-
assert.alwaysCalledWithExactly(getErrorPayloadForClientErrorCodeStub, {
|
|
1798
|
+
assert.alwaysCalledWithExactly(getErrorPayloadForClientErrorCodeStub, {
|
|
1799
|
+
clientErrorCode: MOCK_CLIENT_ERROR_CODE,
|
|
1800
|
+
});
|
|
1769
1801
|
|
|
1770
1802
|
assert.calledThrice(webex.internal.newMetrics.submitClientEvent);
|
|
1771
|
-
assert.calledWith(webex.internal.newMetrics.submitClientEvent.firstCall,
|
|
1803
|
+
assert.calledWith(webex.internal.newMetrics.submitClientEvent.firstCall, {
|
|
1772
1804
|
name: 'client.media.capabilities',
|
|
1773
1805
|
payload: {
|
|
1774
1806
|
mediaCapabilities: {
|
|
@@ -1818,18 +1850,26 @@ describe('plugin-meetings', () => {
|
|
|
1818
1850
|
// Turn discovery internal events are sent twice this time as we go through establishMediaConnection a second time on the retry
|
|
1819
1851
|
const submitInternalEventCalls = webex.internal.newMetrics.submitInternalEvent.getCalls();
|
|
1820
1852
|
assert.equal(submitInternalEventCalls.length, 4);
|
|
1821
|
-
assert.deepEqual(submitInternalEventCalls[0].args, [
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1853
|
+
assert.deepEqual(submitInternalEventCalls[0].args, [
|
|
1854
|
+
{
|
|
1855
|
+
name: 'internal.client.add-media.turn-discovery.start',
|
|
1856
|
+
},
|
|
1857
|
+
]);
|
|
1858
|
+
assert.deepEqual(submitInternalEventCalls[1].args, [
|
|
1859
|
+
{
|
|
1860
|
+
name: 'internal.client.add-media.turn-discovery.end',
|
|
1861
|
+
},
|
|
1862
|
+
]);
|
|
1863
|
+
assert.deepEqual(submitInternalEventCalls[2].args, [
|
|
1864
|
+
{
|
|
1865
|
+
name: 'internal.client.add-media.turn-discovery.start',
|
|
1866
|
+
},
|
|
1867
|
+
]);
|
|
1868
|
+
assert.deepEqual(submitInternalEventCalls[3].args, [
|
|
1869
|
+
{
|
|
1870
|
+
name: 'internal.client.add-media.turn-discovery.end',
|
|
1871
|
+
},
|
|
1872
|
+
]);
|
|
1833
1873
|
|
|
1834
1874
|
const sendBehavioralMetricCalls = Metrics.sendBehavioralMetric.getCalls();
|
|
1835
1875
|
assert.equal(sendBehavioralMetricCalls.length, 3);
|
|
@@ -1872,16 +1912,8 @@ describe('plugin-meetings', () => {
|
|
|
1872
1912
|
// Check that doTurnDiscovery is called with th4 correct value of isForced
|
|
1873
1913
|
const doTurnDiscoveryCalls = meeting.roap.doTurnDiscovery.getCalls();
|
|
1874
1914
|
assert.equal(doTurnDiscoveryCalls.length, 2);
|
|
1875
|
-
assert.deepEqual(doTurnDiscoveryCalls[0].args, [
|
|
1876
|
-
|
|
1877
|
-
false,
|
|
1878
|
-
false
|
|
1879
|
-
]);
|
|
1880
|
-
assert.deepEqual(doTurnDiscoveryCalls[1].args, [
|
|
1881
|
-
meeting,
|
|
1882
|
-
true,
|
|
1883
|
-
true
|
|
1884
|
-
]);
|
|
1915
|
+
assert.deepEqual(doTurnDiscoveryCalls[0].args, [meeting, false, false]);
|
|
1916
|
+
assert.deepEqual(doTurnDiscoveryCalls[1].args, [meeting, true, true]);
|
|
1885
1917
|
|
|
1886
1918
|
// Some clean up steps happens twice
|
|
1887
1919
|
assert.calledTwice(forceRtcMetricsSend);
|
|
@@ -1893,9 +1925,9 @@ describe('plugin-meetings', () => {
|
|
|
1893
1925
|
|
|
1894
1926
|
it('should resolve if waitForMediaConnectionConnected() rejects the first time but resolves the second time', async () => {
|
|
1895
1927
|
const FAKE_ERROR = {fatal: true};
|
|
1896
|
-
const getErrorPayloadForClientErrorCodeStub =
|
|
1897
|
-
.
|
|
1898
|
-
|
|
1928
|
+
const getErrorPayloadForClientErrorCodeStub =
|
|
1929
|
+
(webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode =
|
|
1930
|
+
sinon.stub().returns(FAKE_ERROR));
|
|
1899
1931
|
const MOCK_CLIENT_ERROR_CODE = 2004;
|
|
1900
1932
|
const generateClientErrorCodeForIceFailureStub = sinon
|
|
1901
1933
|
.stub(CallDiagnosticUtils, 'generateClientErrorCodeForIceFailure')
|
|
@@ -1906,18 +1938,28 @@ describe('plugin-meetings', () => {
|
|
|
1906
1938
|
let errorThrown = undefined;
|
|
1907
1939
|
|
|
1908
1940
|
meeting.meetingState = 'ACTIVE';
|
|
1909
|
-
meeting.roap.doTurnDiscovery = sinon
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1941
|
+
meeting.roap.doTurnDiscovery = sinon
|
|
1942
|
+
.stub()
|
|
1943
|
+
.onFirstCall()
|
|
1944
|
+
.returns({
|
|
1945
|
+
turnServerInfo: undefined,
|
|
1946
|
+
turnDiscoverySkippedReason: 'reachability',
|
|
1947
|
+
})
|
|
1948
|
+
.onSecondCall()
|
|
1949
|
+
.returns({
|
|
1950
|
+
turnServerInfo: {
|
|
1951
|
+
url: FAKE_TURN_URL,
|
|
1952
|
+
username: FAKE_TURN_USER,
|
|
1953
|
+
password: FAKE_TURN_PASSWORD,
|
|
1954
|
+
},
|
|
1955
|
+
turnDiscoverySkippedReason: undefined,
|
|
1956
|
+
});
|
|
1957
|
+
meeting.mediaProperties.waitForMediaConnectionConnected = sinon
|
|
1958
|
+
.stub()
|
|
1959
|
+
.onFirstCall()
|
|
1960
|
+
.rejects()
|
|
1961
|
+
.onSecondCall()
|
|
1962
|
+
.resolves();
|
|
1921
1963
|
|
|
1922
1964
|
const forceRtcMetricsSend = sinon.stub().resolves();
|
|
1923
1965
|
const closeMediaConnectionStub = sinon.stub();
|
|
@@ -1942,10 +1984,12 @@ describe('plugin-meetings', () => {
|
|
|
1942
1984
|
signalingState: 'unknown',
|
|
1943
1985
|
iceConnectionState: 'unknown',
|
|
1944
1986
|
turnServerUsed: false,
|
|
1945
|
-
})
|
|
1987
|
+
});
|
|
1946
1988
|
|
|
1947
1989
|
assert.calledOnce(getErrorPayloadForClientErrorCodeStub);
|
|
1948
|
-
assert.calledWith(getErrorPayloadForClientErrorCodeStub, {
|
|
1990
|
+
assert.calledWith(getErrorPayloadForClientErrorCodeStub, {
|
|
1991
|
+
clientErrorCode: MOCK_CLIENT_ERROR_CODE,
|
|
1992
|
+
});
|
|
1949
1993
|
|
|
1950
1994
|
assert.calledThrice(webex.internal.newMetrics.submitClientEvent);
|
|
1951
1995
|
assert.calledWith(webex.internal.newMetrics.submitClientEvent.firstCall, {
|
|
@@ -1993,18 +2037,26 @@ describe('plugin-meetings', () => {
|
|
|
1993
2037
|
// Turn discovery internal events are sent twice this time as we go through establishMediaConnection a second time on the retry
|
|
1994
2038
|
const submitInternalEventCalls = webex.internal.newMetrics.submitInternalEvent.getCalls();
|
|
1995
2039
|
assert.equal(submitInternalEventCalls.length, 4);
|
|
1996
|
-
assert.deepEqual(submitInternalEventCalls[0].args, [
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2040
|
+
assert.deepEqual(submitInternalEventCalls[0].args, [
|
|
2041
|
+
{
|
|
2042
|
+
name: 'internal.client.add-media.turn-discovery.start',
|
|
2043
|
+
},
|
|
2044
|
+
]);
|
|
2045
|
+
assert.deepEqual(submitInternalEventCalls[1].args, [
|
|
2046
|
+
{
|
|
2047
|
+
name: 'internal.client.add-media.turn-discovery.end',
|
|
2048
|
+
},
|
|
2049
|
+
]);
|
|
2050
|
+
assert.deepEqual(submitInternalEventCalls[2].args, [
|
|
2051
|
+
{
|
|
2052
|
+
name: 'internal.client.add-media.turn-discovery.start',
|
|
2053
|
+
},
|
|
2054
|
+
]);
|
|
2055
|
+
assert.deepEqual(submitInternalEventCalls[3].args, [
|
|
2056
|
+
{
|
|
2057
|
+
name: 'internal.client.add-media.turn-discovery.end',
|
|
2058
|
+
},
|
|
2059
|
+
]);
|
|
2008
2060
|
|
|
2009
2061
|
const sendBehavioralMetricCalls = Metrics.sendBehavioralMetric.getCalls();
|
|
2010
2062
|
assert.equal(sendBehavioralMetricCalls.length, 3);
|
|
@@ -2036,21 +2088,13 @@ describe('plugin-meetings', () => {
|
|
|
2036
2088
|
retriedWithTurnServer: true,
|
|
2037
2089
|
},
|
|
2038
2090
|
]);
|
|
2039
|
-
meeting.roap.doTurnDiscovery
|
|
2091
|
+
meeting.roap.doTurnDiscovery;
|
|
2040
2092
|
|
|
2041
2093
|
// Check that doTurnDiscovery is called with th4 correct value of isForced
|
|
2042
2094
|
const doTurnDiscoveryCalls = meeting.roap.doTurnDiscovery.getCalls();
|
|
2043
2095
|
assert.equal(doTurnDiscoveryCalls.length, 2);
|
|
2044
|
-
assert.deepEqual(doTurnDiscoveryCalls[0].args, [
|
|
2045
|
-
|
|
2046
|
-
false,
|
|
2047
|
-
false
|
|
2048
|
-
]);
|
|
2049
|
-
assert.deepEqual(doTurnDiscoveryCalls[1].args, [
|
|
2050
|
-
meeting,
|
|
2051
|
-
true,
|
|
2052
|
-
true
|
|
2053
|
-
]);
|
|
2096
|
+
assert.deepEqual(doTurnDiscoveryCalls[0].args, [meeting, false, false]);
|
|
2097
|
+
assert.deepEqual(doTurnDiscoveryCalls[1].args, [meeting, true, true]);
|
|
2054
2098
|
|
|
2055
2099
|
assert.calledOnce(forceRtcMetricsSend);
|
|
2056
2100
|
assert.calledOnce(closeMediaConnectionStub);
|
|
@@ -2066,18 +2110,28 @@ describe('plugin-meetings', () => {
|
|
|
2066
2110
|
|
|
2067
2111
|
meeting.meetingState = 'ACTIVE';
|
|
2068
2112
|
meeting.state = 'LEFT';
|
|
2069
|
-
meeting.roap.doTurnDiscovery = sinon
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2113
|
+
meeting.roap.doTurnDiscovery = sinon
|
|
2114
|
+
.stub()
|
|
2115
|
+
.onFirstCall()
|
|
2116
|
+
.returns({
|
|
2117
|
+
turnServerInfo: undefined,
|
|
2118
|
+
turnDiscoverySkippedReason: 'reachability',
|
|
2119
|
+
})
|
|
2120
|
+
.onSecondCall()
|
|
2121
|
+
.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
|
|
2130
|
+
.stub()
|
|
2131
|
+
.onFirstCall()
|
|
2132
|
+
.rejects()
|
|
2133
|
+
.onSecondCall()
|
|
2134
|
+
.resolves();
|
|
2081
2135
|
meeting.join = sinon.stub().resolves();
|
|
2082
2136
|
|
|
2083
2137
|
const closeMediaConnectionStub = sinon.stub();
|
|
@@ -2108,18 +2162,28 @@ describe('plugin-meetings', () => {
|
|
|
2108
2162
|
|
|
2109
2163
|
meeting.meetingState = 'ACTIVE';
|
|
2110
2164
|
meeting.state = 'LEFT';
|
|
2111
|
-
meeting.roap.doTurnDiscovery = sinon
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2165
|
+
meeting.roap.doTurnDiscovery = sinon
|
|
2166
|
+
.stub()
|
|
2167
|
+
.onFirstCall()
|
|
2168
|
+
.returns({
|
|
2169
|
+
turnServerInfo: undefined,
|
|
2170
|
+
turnDiscoverySkippedReason: 'reachability',
|
|
2171
|
+
})
|
|
2172
|
+
.onSecondCall()
|
|
2173
|
+
.returns({
|
|
2174
|
+
turnServerInfo: {
|
|
2175
|
+
url: FAKE_TURN_URL,
|
|
2176
|
+
username: FAKE_TURN_USER,
|
|
2177
|
+
password: FAKE_TURN_PASSWORD,
|
|
2178
|
+
},
|
|
2179
|
+
turnDiscoverySkippedReason: undefined,
|
|
2180
|
+
});
|
|
2181
|
+
meeting.mediaProperties.waitForMediaConnectionConnected = sinon
|
|
2182
|
+
.stub()
|
|
2183
|
+
.onFirstCall()
|
|
2184
|
+
.rejects()
|
|
2185
|
+
.onSecondCall()
|
|
2186
|
+
.resolves();
|
|
2123
2187
|
meeting.join = sinon.stub().rejects();
|
|
2124
2188
|
|
|
2125
2189
|
const closeMediaConnectionStub = sinon.stub();
|
|
@@ -2147,7 +2211,7 @@ describe('plugin-meetings', () => {
|
|
|
2147
2211
|
meeting.webex.meetings.reachability = {
|
|
2148
2212
|
getReachabilityMetrics: sinon.stub().resolves({
|
|
2149
2213
|
someReachabilityMetric1: 'some value1',
|
|
2150
|
-
someReachabilityMetric2: 'some value2'
|
|
2214
|
+
someReachabilityMetric2: 'some value2',
|
|
2151
2215
|
}),
|
|
2152
2216
|
};
|
|
2153
2217
|
await meeting.addMedia({
|
|
@@ -2209,7 +2273,8 @@ describe('plugin-meetings', () => {
|
|
|
2209
2273
|
});
|
|
2210
2274
|
|
|
2211
2275
|
// Check that the only metric sent is ADD_MEDIA_FAILURE
|
|
2212
|
-
assert.calledOnceWithExactly(
|
|
2276
|
+
assert.calledOnceWithExactly(
|
|
2277
|
+
Metrics.sendBehavioralMetric,
|
|
2213
2278
|
BEHAVIORAL_METRICS.ADD_MEDIA_FAILURE,
|
|
2214
2279
|
{
|
|
2215
2280
|
correlation_id: meeting.correlationId,
|
|
@@ -2549,550 +2614,609 @@ describe('plugin-meetings', () => {
|
|
|
2549
2614
|
to @webex/internal-media-core when addMedia, updateMedia, publishTracks, unpublishTracks are called
|
|
2550
2615
|
in various combinations.
|
|
2551
2616
|
*/
|
|
2552
|
-
[true,false].forEach((isMultistream) =>
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2617
|
+
[true, false].forEach((isMultistream) =>
|
|
2618
|
+
describe(`addMedia/updateMedia semi-integration tests (${
|
|
2619
|
+
isMultistream ? 'multistream' : 'transcoded'
|
|
2620
|
+
})`, () => {
|
|
2621
|
+
let fakeMicrophoneStream;
|
|
2622
|
+
let fakeRoapMediaConnection;
|
|
2623
|
+
let fakeMultistreamRoapMediaConnection;
|
|
2624
|
+
let roapMediaConnectionConstructorStub;
|
|
2625
|
+
let multistreamRoapMediaConnectionConstructorStub;
|
|
2626
|
+
let locusMediaRequestStub; // stub for /media requests to Locus
|
|
2560
2627
|
|
|
2561
|
-
|
|
2562
|
-
|
|
2628
|
+
const roapOfferMessage = {messageType: 'OFFER', sdp: 'sdp', seq: '1', tieBreaker: '123'};
|
|
2629
|
+
const roapOKMessage = {messageType: 'OK', seq: '1'};
|
|
2563
2630
|
|
|
2564
|
-
|
|
2565
|
-
|
|
2631
|
+
let expectedMediaConnectionConfig;
|
|
2632
|
+
let expectedDebugId;
|
|
2566
2633
|
|
|
2567
|
-
|
|
2634
|
+
let clock;
|
|
2568
2635
|
|
|
2569
|
-
|
|
2570
|
-
|
|
2636
|
+
beforeEach(() => {
|
|
2637
|
+
clock = sinon.useFakeTimers();
|
|
2571
2638
|
|
|
2572
|
-
|
|
2639
|
+
sinon.stub(MeetingUtil, 'getIpVersion').returns(IP_VERSION.unknown);
|
|
2573
2640
|
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2641
|
+
meeting.deviceUrl = 'deviceUrl';
|
|
2642
|
+
meeting.config.deviceType = 'web';
|
|
2643
|
+
meeting.isMultistream = isMultistream;
|
|
2644
|
+
meeting.meetingState = 'ACTIVE';
|
|
2645
|
+
meeting.mediaId = 'fake media id';
|
|
2646
|
+
meeting.selfUrl = 'selfUrl';
|
|
2647
|
+
meeting.mediaProperties.waitForMediaConnectionConnected = sinon.stub().resolves();
|
|
2648
|
+
meeting.mediaProperties.getCurrentConnectionType = sinon.stub().resolves('udp');
|
|
2649
|
+
meeting.setMercuryListener = sinon.stub();
|
|
2650
|
+
meeting.locusInfo.onFullLocus = sinon.stub();
|
|
2651
|
+
meeting.webex.meetings.geoHintInfo = {regionCode: 'EU', countryCode: 'UK'};
|
|
2652
|
+
meeting.roap.doTurnDiscovery = sinon
|
|
2653
|
+
.stub()
|
|
2654
|
+
.resolves({turnServerInfo: {}, turnDiscoverySkippedReason: 'reachability'});
|
|
2655
|
+
meeting.deferSDPAnswer = new Defer();
|
|
2656
|
+
meeting.deferSDPAnswer.resolve();
|
|
2657
|
+
meeting.webex.meetings.meetingCollection = new MeetingCollection();
|
|
2658
|
+
meeting.webex.meetings.meetingCollection.set(meeting);
|
|
2659
|
+
|
|
2660
|
+
StaticConfig.set({bandwidth: {audio: 1234, video: 5678, startBitrate: 9876}});
|
|
2661
|
+
|
|
2662
|
+
// setup things that are expected to be the same across all the tests and are actually irrelevant for these tests
|
|
2663
|
+
expectedDebugId = `MC-${meeting.id.substring(0, 4)}`;
|
|
2664
|
+
expectedMediaConnectionConfig = {
|
|
2665
|
+
iceServers: [{urls: undefined, username: '', credential: ''}],
|
|
2666
|
+
skipInactiveTransceivers: false,
|
|
2667
|
+
requireH264: true,
|
|
2668
|
+
sdpMunging: {
|
|
2669
|
+
convertPort9to0: false,
|
|
2670
|
+
addContentSlides: true,
|
|
2671
|
+
bandwidthLimits: {
|
|
2672
|
+
audio: StaticConfig.meetings.bandwidth.audio,
|
|
2673
|
+
video: StaticConfig.meetings.bandwidth.video,
|
|
2674
|
+
},
|
|
2675
|
+
startBitrate: StaticConfig.meetings.bandwidth.startBitrate,
|
|
2676
|
+
periodicKeyframes: 20,
|
|
2677
|
+
disableExtmap: !meeting.config.enableExtmap,
|
|
2678
|
+
disableRtx: !meeting.config.enableRtx,
|
|
2607
2679
|
},
|
|
2608
|
-
|
|
2609
|
-
periodicKeyframes: 20,
|
|
2610
|
-
disableExtmap: !meeting.config.enableExtmap,
|
|
2611
|
-
disableRtx: !meeting.config.enableRtx,
|
|
2612
|
-
},
|
|
2613
|
-
};
|
|
2680
|
+
};
|
|
2614
2681
|
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2682
|
+
// setup stubs
|
|
2683
|
+
fakeMicrophoneStream = {
|
|
2684
|
+
on: sinon.stub(),
|
|
2685
|
+
off: sinon.stub(),
|
|
2686
|
+
getSettings: sinon.stub().returns({
|
|
2687
|
+
deviceId: 'some device id',
|
|
2688
|
+
}),
|
|
2689
|
+
muted: false,
|
|
2690
|
+
setUnmuteAllowed: sinon.stub(),
|
|
2691
|
+
setMuted: sinon.stub(),
|
|
2692
|
+
setServerMuted: sinon.stub(),
|
|
2693
|
+
outputStream: {
|
|
2694
|
+
getTracks: () => {
|
|
2695
|
+
return [
|
|
2696
|
+
{
|
|
2697
|
+
id: 'fake mic',
|
|
2698
|
+
},
|
|
2699
|
+
];
|
|
2700
|
+
},
|
|
2701
|
+
},
|
|
2702
|
+
};
|
|
2634
2703
|
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2704
|
+
fakeRoapMediaConnection = {
|
|
2705
|
+
id: 'roap media connection',
|
|
2706
|
+
close: sinon.stub(),
|
|
2707
|
+
getConnectionState: sinon.stub().returns(ConnectionState.Connected),
|
|
2708
|
+
initiateOffer: sinon.stub().resolves({}),
|
|
2709
|
+
update: sinon.stub().resolves({}),
|
|
2710
|
+
on: sinon.stub(),
|
|
2711
|
+
};
|
|
2643
2712
|
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2713
|
+
fakeMultistreamRoapMediaConnection = {
|
|
2714
|
+
id: 'multistream roap media connection',
|
|
2715
|
+
close: sinon.stub(),
|
|
2716
|
+
getConnectionState: sinon.stub().returns(ConnectionState.Connected),
|
|
2717
|
+
initiateOffer: sinon.stub().resolves({}),
|
|
2718
|
+
on: sinon.stub(),
|
|
2719
|
+
requestMedia: sinon.stub(),
|
|
2720
|
+
createReceiveSlot: sinon.stub().resolves({on: sinon.stub()}),
|
|
2721
|
+
createSendSlot: sinon.stub().returns({
|
|
2722
|
+
publishStream: sinon.stub(),
|
|
2723
|
+
unpublishStream: sinon.stub(),
|
|
2724
|
+
}),
|
|
2725
|
+
enableMultistreamAudio: sinon.stub(),
|
|
2726
|
+
};
|
|
2658
2727
|
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2728
|
+
roapMediaConnectionConstructorStub = sinon
|
|
2729
|
+
.stub(internalMediaModule, 'RoapMediaConnection')
|
|
2730
|
+
.returns(fakeRoapMediaConnection);
|
|
2662
2731
|
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2732
|
+
multistreamRoapMediaConnectionConstructorStub = sinon
|
|
2733
|
+
.stub(internalMediaModule, 'MultistreamRoapMediaConnection')
|
|
2734
|
+
.returns(fakeMultistreamRoapMediaConnection);
|
|
2666
2735
|
|
|
2667
|
-
|
|
2668
|
-
|
|
2736
|
+
locusMediaRequestStub = sinon
|
|
2737
|
+
.stub(WebexPlugin.prototype, 'request')
|
|
2738
|
+
.resolves({body: {locus: {fullState: {}}}});
|
|
2739
|
+
});
|
|
2669
2740
|
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2741
|
+
afterEach(() => {
|
|
2742
|
+
clock.restore();
|
|
2743
|
+
sinon.restore();
|
|
2744
|
+
});
|
|
2674
2745
|
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2746
|
+
// helper function that waits until all promises are resolved and any queued up /media requests to Locus are sent out
|
|
2747
|
+
const stableState = async () => {
|
|
2748
|
+
await testUtils.flushPromises();
|
|
2749
|
+
clock.tick(1); // needed because LocusMediaRequest uses Lodash.defer()
|
|
2750
|
+
};
|
|
2680
2751
|
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
};
|
|
2752
|
+
const resetHistory = () => {
|
|
2753
|
+
locusMediaRequestStub.resetHistory();
|
|
2754
|
+
fakeRoapMediaConnection.update.resetHistory();
|
|
2755
|
+
try {
|
|
2756
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream.resetHistory();
|
|
2757
|
+
} catch (e) {}
|
|
2758
|
+
};
|
|
2689
2759
|
|
|
2690
|
-
|
|
2691
|
-
|
|
2760
|
+
const getRoapListener = () => {
|
|
2761
|
+
const roapMediaConnectionToCheck = isMultistream
|
|
2762
|
+
? fakeMultistreamRoapMediaConnection
|
|
2763
|
+
: fakeRoapMediaConnection;
|
|
2692
2764
|
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2765
|
+
for (let idx = 0; idx < roapMediaConnectionToCheck.on.callCount; idx += 1) {
|
|
2766
|
+
if (
|
|
2767
|
+
roapMediaConnectionToCheck.on.getCall(idx).args[0] === Event.ROAP_MESSAGE_TO_SEND
|
|
2768
|
+
) {
|
|
2769
|
+
return roapMediaConnectionToCheck.on.getCall(idx).args[1];
|
|
2770
|
+
}
|
|
2696
2771
|
}
|
|
2772
|
+
assert.fail(
|
|
2773
|
+
'listener for "roap:messageToSend" (Event.ROAP_MESSAGE_TO_SEND) was not registered'
|
|
2774
|
+
);
|
|
2697
2775
|
};
|
|
2698
|
-
assert.fail(
|
|
2699
|
-
'listener for "roap:messageToSend" (Event.ROAP_MESSAGE_TO_SEND) was not registered'
|
|
2700
|
-
);
|
|
2701
|
-
};
|
|
2702
2776
|
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2777
|
+
// simulates a Roap offer being generated by the RoapMediaConnection
|
|
2778
|
+
const simulateRoapOffer = async () => {
|
|
2779
|
+
meeting.deferSDPAnswer = {resolve: sinon.stub()};
|
|
2780
|
+
const roapListener = getRoapListener();
|
|
2707
2781
|
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2782
|
+
await roapListener({roapMessage: roapOfferMessage});
|
|
2783
|
+
await stableState();
|
|
2784
|
+
};
|
|
2711
2785
|
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2786
|
+
// simulates a Roap OK being sent
|
|
2787
|
+
const simulateRoapOk = async () => {
|
|
2788
|
+
const roapListener = getRoapListener();
|
|
2715
2789
|
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2790
|
+
await roapListener({roapMessage: roapOKMessage});
|
|
2791
|
+
await stableState();
|
|
2792
|
+
};
|
|
2719
2793
|
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2794
|
+
const checkSdpOfferSent = ({audioMuted, videoMuted}) => {
|
|
2795
|
+
const {sdp, seq, tieBreaker} = roapOfferMessage;
|
|
2796
|
+
|
|
2797
|
+
assert.calledWith(locusMediaRequestStub, {
|
|
2798
|
+
method: 'PUT',
|
|
2799
|
+
uri: `${meeting.selfUrl}/media`,
|
|
2800
|
+
body: {
|
|
2801
|
+
device: {
|
|
2802
|
+
url: meeting.deviceUrl,
|
|
2803
|
+
deviceType: meeting.config.deviceType,
|
|
2804
|
+
regionCode: 'EU',
|
|
2805
|
+
countryCode: 'UK',
|
|
2806
|
+
},
|
|
2807
|
+
correlationId: meeting.correlationId,
|
|
2808
|
+
localMedias: [
|
|
2809
|
+
{
|
|
2810
|
+
localSdp: `{"audioMuted":${audioMuted},"videoMuted":${videoMuted},"roapMessage":{"messageType":"OFFER","sdps":["${sdp}"],"version":"2","seq":"${seq}","tieBreaker":"${tieBreaker}","headers":["includeAnswerInHttpResponse","noOkInTransaction"]}}`,
|
|
2811
|
+
mediaId: 'fake media id',
|
|
2812
|
+
},
|
|
2813
|
+
],
|
|
2814
|
+
clientMediaPreferences: {
|
|
2815
|
+
preferTranscoding: !meeting.isMultistream,
|
|
2816
|
+
joinCookie: undefined,
|
|
2817
|
+
ipver: 0,
|
|
2738
2818
|
},
|
|
2739
|
-
],
|
|
2740
|
-
clientMediaPreferences: {
|
|
2741
|
-
preferTranscoding: !meeting.isMultistream,
|
|
2742
|
-
joinCookie: undefined,
|
|
2743
|
-
ipver: 0,
|
|
2744
2819
|
},
|
|
2745
|
-
}
|
|
2746
|
-
}
|
|
2747
|
-
};
|
|
2820
|
+
});
|
|
2821
|
+
};
|
|
2748
2822
|
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
},
|
|
2762
|
-
correlationId: meeting.correlationId,
|
|
2763
|
-
clientMediaPreferences: {
|
|
2764
|
-
preferTranscoding: !meeting.isMultistream,
|
|
2765
|
-
ipver: undefined,
|
|
2766
|
-
joinCookie: undefined
|
|
2767
|
-
},
|
|
2768
|
-
localMedias: [
|
|
2769
|
-
{
|
|
2770
|
-
localSdp: `{"audioMuted":${audioMuted},"videoMuted":${videoMuted},"roapMessage":{"messageType":"OK","version":"2","seq":"${seq}"}}`,
|
|
2771
|
-
mediaId: 'fake media id'
|
|
2823
|
+
const checkOkSent = ({audioMuted, videoMuted}) => {
|
|
2824
|
+
const {seq} = roapOKMessage;
|
|
2825
|
+
|
|
2826
|
+
assert.calledWith(locusMediaRequestStub, {
|
|
2827
|
+
method: 'PUT',
|
|
2828
|
+
uri: `${meeting.selfUrl}/media`,
|
|
2829
|
+
body: {
|
|
2830
|
+
device: {
|
|
2831
|
+
url: meeting.deviceUrl,
|
|
2832
|
+
deviceType: meeting.config.deviceType,
|
|
2833
|
+
countryCode: 'UK',
|
|
2834
|
+
regionCode: 'EU',
|
|
2772
2835
|
},
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2836
|
+
correlationId: meeting.correlationId,
|
|
2837
|
+
clientMediaPreferences: {
|
|
2838
|
+
preferTranscoding: !meeting.isMultistream,
|
|
2839
|
+
ipver: undefined,
|
|
2840
|
+
joinCookie: undefined,
|
|
2841
|
+
},
|
|
2842
|
+
localMedias: [
|
|
2843
|
+
{
|
|
2844
|
+
localSdp: `{"audioMuted":${audioMuted},"videoMuted":${videoMuted},"roapMessage":{"messageType":"OK","version":"2","seq":"${seq}"}}`,
|
|
2845
|
+
mediaId: 'fake media id',
|
|
2846
|
+
},
|
|
2847
|
+
],
|
|
2848
|
+
},
|
|
2849
|
+
});
|
|
2850
|
+
};
|
|
2777
2851
|
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2852
|
+
const checkLocalMuteSentToLocus = ({audioMuted, videoMuted}) => {
|
|
2853
|
+
assert.calledWith(locusMediaRequestStub, {
|
|
2854
|
+
method: 'PUT',
|
|
2855
|
+
uri: `${meeting.selfUrl}/media`,
|
|
2856
|
+
body: {
|
|
2857
|
+
device: {
|
|
2858
|
+
url: meeting.deviceUrl,
|
|
2859
|
+
deviceType: meeting.config.deviceType,
|
|
2860
|
+
regionCode: 'EU',
|
|
2861
|
+
countryCode: 'UK',
|
|
2862
|
+
},
|
|
2863
|
+
correlationId: meeting.correlationId,
|
|
2864
|
+
localMedias: [
|
|
2865
|
+
{
|
|
2866
|
+
localSdp: `{"audioMuted":${audioMuted},"videoMuted":${videoMuted}}`,
|
|
2867
|
+
mediaId: 'fake media id',
|
|
2868
|
+
},
|
|
2869
|
+
],
|
|
2870
|
+
clientMediaPreferences: {
|
|
2871
|
+
preferTranscoding: !meeting.isMultistream,
|
|
2872
|
+
ipver: undefined,
|
|
2873
|
+
},
|
|
2874
|
+
respOnlySdp: true,
|
|
2875
|
+
usingResource: null,
|
|
2788
2876
|
},
|
|
2789
|
-
|
|
2790
|
-
|
|
2877
|
+
});
|
|
2878
|
+
};
|
|
2879
|
+
|
|
2880
|
+
const checkMediaConnectionCreated = ({
|
|
2881
|
+
mediaConnectionConfig,
|
|
2882
|
+
localStreams,
|
|
2883
|
+
direction,
|
|
2884
|
+
remoteQualityLevel,
|
|
2885
|
+
expectedDebugId,
|
|
2886
|
+
meetingId,
|
|
2887
|
+
}) => {
|
|
2888
|
+
if (isMultistream) {
|
|
2889
|
+
const {iceServers} = mediaConnectionConfig;
|
|
2890
|
+
|
|
2891
|
+
assert.calledOnceWithMatch(
|
|
2892
|
+
multistreamRoapMediaConnectionConstructorStub,
|
|
2791
2893
|
{
|
|
2792
|
-
|
|
2793
|
-
mediaId: 'fake media id',
|
|
2894
|
+
iceServers,
|
|
2794
2895
|
},
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2896
|
+
meetingId
|
|
2897
|
+
);
|
|
2898
|
+
|
|
2899
|
+
assert.calledWith(
|
|
2900
|
+
fakeMultistreamRoapMediaConnection.createSendSlot,
|
|
2901
|
+
MediaType.AudioMain,
|
|
2902
|
+
direction.audio !== 'inactive'
|
|
2903
|
+
);
|
|
2904
|
+
assert.calledWith(
|
|
2905
|
+
fakeMultistreamRoapMediaConnection.createSendSlot,
|
|
2906
|
+
MediaType.VideoMain,
|
|
2907
|
+
direction.video !== 'inactive'
|
|
2908
|
+
);
|
|
2909
|
+
assert.calledWith(
|
|
2910
|
+
fakeMultistreamRoapMediaConnection.createSendSlot,
|
|
2911
|
+
MediaType.AudioSlides,
|
|
2912
|
+
direction.screenShare !== 'inactive'
|
|
2913
|
+
);
|
|
2914
|
+
assert.calledWith(
|
|
2915
|
+
fakeMultistreamRoapMediaConnection.createSendSlot,
|
|
2916
|
+
MediaType.VideoSlides,
|
|
2917
|
+
direction.screenShare !== 'inactive'
|
|
2918
|
+
);
|
|
2805
2919
|
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2920
|
+
for (let type in localStreams) {
|
|
2921
|
+
const stream = localStreams[type];
|
|
2922
|
+
if (stream !== undefined) {
|
|
2923
|
+
switch (type) {
|
|
2924
|
+
case 'audio':
|
|
2925
|
+
assert.calledOnceWithExactly(
|
|
2926
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream,
|
|
2927
|
+
stream
|
|
2928
|
+
);
|
|
2929
|
+
break;
|
|
2930
|
+
case 'video':
|
|
2931
|
+
assert.calledOnceWithExactly(
|
|
2932
|
+
meeting.sendSlotManager.getSlot(MediaType.VideoMain).publishStream,
|
|
2933
|
+
stream
|
|
2934
|
+
);
|
|
2935
|
+
break;
|
|
2936
|
+
case 'screenShareAudio':
|
|
2937
|
+
assert.calledOnceWithExactly(
|
|
2938
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioSlides).publishStream,
|
|
2939
|
+
stream
|
|
2940
|
+
);
|
|
2941
|
+
break;
|
|
2942
|
+
case 'screenShareVideo':
|
|
2943
|
+
assert.calledOnceWithExactly(
|
|
2944
|
+
meeting.sendSlotManager.getSlot(MediaType.VideoSlides).publishStream,
|
|
2945
|
+
stream
|
|
2946
|
+
);
|
|
2947
|
+
break;
|
|
2948
|
+
}
|
|
2835
2949
|
}
|
|
2836
2950
|
}
|
|
2837
|
-
}
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2951
|
+
} else {
|
|
2952
|
+
assert.calledOnceWithExactly(
|
|
2953
|
+
roapMediaConnectionConstructorStub,
|
|
2954
|
+
mediaConnectionConfig,
|
|
2955
|
+
{
|
|
2956
|
+
localTracks: {
|
|
2957
|
+
audio: localStreams.audio?.outputStream?.getTracks()[0],
|
|
2958
|
+
video: localStreams.video?.outputStream?.getTracks()[0],
|
|
2959
|
+
screenShareVideo: localStreams.screenShareVideo?.outputStream?.getTracks()[0],
|
|
2960
|
+
screenShareAudio: localStreams.screenShareAudio?.outputStream?.getTracks()[0],
|
|
2961
|
+
},
|
|
2962
|
+
direction: {
|
|
2963
|
+
audio: direction.audio,
|
|
2964
|
+
video: direction.video,
|
|
2965
|
+
screenShareVideo: direction.screenShare,
|
|
2966
|
+
},
|
|
2967
|
+
remoteQualityLevel,
|
|
2846
2968
|
},
|
|
2847
|
-
|
|
2848
|
-
|
|
2969
|
+
expectedDebugId
|
|
2970
|
+
);
|
|
2971
|
+
}
|
|
2972
|
+
};
|
|
2973
|
+
|
|
2974
|
+
it('addMedia() works correctly when media is enabled without tracks to publish', async () => {
|
|
2975
|
+
await meeting.addMedia();
|
|
2976
|
+
await simulateRoapOffer();
|
|
2977
|
+
await simulateRoapOk();
|
|
2978
|
+
|
|
2979
|
+
// check RoapMediaConnection was created correctly
|
|
2980
|
+
checkMediaConnectionCreated({
|
|
2981
|
+
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
2982
|
+
localStreams: {
|
|
2983
|
+
audio: undefined,
|
|
2984
|
+
video: undefined,
|
|
2985
|
+
screenShareVideo: undefined,
|
|
2986
|
+
screenShareAudio: undefined,
|
|
2849
2987
|
},
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2988
|
+
direction: {
|
|
2989
|
+
audio: 'sendrecv',
|
|
2990
|
+
video: 'sendrecv',
|
|
2991
|
+
screenShare: 'recvonly',
|
|
2992
|
+
},
|
|
2993
|
+
remoteQualityLevel: 'HIGH',
|
|
2994
|
+
expectedDebugId,
|
|
2995
|
+
meetingId: meeting.id,
|
|
2996
|
+
});
|
|
2854
2997
|
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
2863
|
-
localStreams: {
|
|
2864
|
-
audio: undefined,
|
|
2865
|
-
video: undefined,
|
|
2866
|
-
screenShareVideo: undefined,
|
|
2867
|
-
screenShareAudio: undefined,
|
|
2868
|
-
},
|
|
2869
|
-
direction: {
|
|
2870
|
-
audio: 'sendrecv',
|
|
2871
|
-
video: 'sendrecv',
|
|
2872
|
-
screenShare: 'recvonly',
|
|
2873
|
-
},
|
|
2874
|
-
remoteQualityLevel: 'HIGH',
|
|
2875
|
-
expectedDebugId,
|
|
2876
|
-
meetingId: meeting.id
|
|
2998
|
+
// and SDP offer was sent with the right audioMuted/videoMuted values
|
|
2999
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3000
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3001
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
3002
|
+
|
|
3003
|
+
// and that these were the only /media requests that were sent
|
|
3004
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
2877
3005
|
});
|
|
2878
3006
|
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
3007
|
+
it('addMedia() works correctly when media is enabled with streams to publish', async () => {
|
|
3008
|
+
await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}});
|
|
3009
|
+
await simulateRoapOffer();
|
|
3010
|
+
await simulateRoapOk();
|
|
2883
3011
|
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
3012
|
+
// check RoapMediaConnection was created correctly
|
|
3013
|
+
checkMediaConnectionCreated({
|
|
3014
|
+
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3015
|
+
localStreams: {
|
|
3016
|
+
audio: fakeMicrophoneStream,
|
|
3017
|
+
video: undefined,
|
|
3018
|
+
screenShareVideo: undefined,
|
|
3019
|
+
screenShareAudio: undefined,
|
|
3020
|
+
},
|
|
3021
|
+
direction: {
|
|
3022
|
+
audio: 'sendrecv',
|
|
3023
|
+
video: 'sendrecv',
|
|
3024
|
+
screenShare: 'recvonly',
|
|
3025
|
+
},
|
|
3026
|
+
remoteQualityLevel: 'HIGH',
|
|
3027
|
+
expectedDebugId,
|
|
3028
|
+
meetingId: meeting.id,
|
|
3029
|
+
});
|
|
2887
3030
|
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
3031
|
+
// and SDP offer was sent with the right audioMuted/videoMuted values
|
|
3032
|
+
checkSdpOfferSent({audioMuted: false, videoMuted: true});
|
|
3033
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3034
|
+
checkOkSent({audioMuted: false, videoMuted: true});
|
|
2892
3035
|
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
2896
|
-
localStreams: {
|
|
2897
|
-
audio: fakeMicrophoneStream,
|
|
2898
|
-
video: undefined,
|
|
2899
|
-
screenShareVideo: undefined,
|
|
2900
|
-
screenShareAudio: undefined,
|
|
2901
|
-
},
|
|
2902
|
-
direction: {
|
|
2903
|
-
audio: 'sendrecv',
|
|
2904
|
-
video: 'sendrecv',
|
|
2905
|
-
screenShare: 'recvonly',
|
|
2906
|
-
},
|
|
2907
|
-
remoteQualityLevel: 'HIGH',
|
|
2908
|
-
expectedDebugId,
|
|
2909
|
-
meetingId: meeting.id
|
|
3036
|
+
// and that these were the only /media requests that were sent
|
|
3037
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
2910
3038
|
});
|
|
2911
3039
|
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
// check OK was sent with the right audioMuted/videoMuted values
|
|
2915
|
-
checkOkSent({audioMuted: false, videoMuted: true});
|
|
3040
|
+
it('addMedia() works correctly when media is enabled with tracks to publish and track is muted', async () => {
|
|
3041
|
+
fakeMicrophoneStream.muted = true;
|
|
2916
3042
|
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
it('addMedia() works correctly when media is enabled with tracks to publish and track is muted', async () => {
|
|
2922
|
-
fakeMicrophoneStream.muted = true;
|
|
3043
|
+
await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}});
|
|
3044
|
+
await simulateRoapOffer();
|
|
3045
|
+
await simulateRoapOk();
|
|
2923
3046
|
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
3047
|
+
// check RoapMediaConnection was created correctly
|
|
3048
|
+
checkMediaConnectionCreated({
|
|
3049
|
+
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3050
|
+
localStreams: {
|
|
3051
|
+
audio: fakeMicrophoneStream,
|
|
3052
|
+
video: undefined,
|
|
3053
|
+
screenShareVideo: undefined,
|
|
3054
|
+
screenShareAudio: undefined,
|
|
3055
|
+
},
|
|
3056
|
+
direction: {
|
|
3057
|
+
audio: 'sendrecv',
|
|
3058
|
+
video: 'sendrecv',
|
|
3059
|
+
screenShare: 'recvonly',
|
|
3060
|
+
},
|
|
3061
|
+
remoteQualityLevel: 'HIGH',
|
|
3062
|
+
expectedDebugId,
|
|
3063
|
+
meetingId: meeting.id,
|
|
3064
|
+
});
|
|
3065
|
+
// and SDP offer was sent with the right audioMuted/videoMuted values
|
|
3066
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3067
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3068
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
2927
3069
|
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
2931
|
-
localStreams: {
|
|
2932
|
-
audio: fakeMicrophoneStream,
|
|
2933
|
-
video: undefined,
|
|
2934
|
-
screenShareVideo: undefined,
|
|
2935
|
-
screenShareAudio: undefined,
|
|
2936
|
-
},
|
|
2937
|
-
direction: {
|
|
2938
|
-
audio: 'sendrecv',
|
|
2939
|
-
video: 'sendrecv',
|
|
2940
|
-
screenShare: 'recvonly',
|
|
2941
|
-
},
|
|
2942
|
-
remoteQualityLevel: 'HIGH',
|
|
2943
|
-
expectedDebugId,
|
|
2944
|
-
meetingId: meeting.id
|
|
2945
|
-
});
|
|
2946
|
-
// and SDP offer was sent with the right audioMuted/videoMuted values
|
|
2947
|
-
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
2948
|
-
// check OK was sent with the right audioMuted/videoMuted values
|
|
2949
|
-
checkOkSent({audioMuted: true, videoMuted: true});
|
|
2950
|
-
|
|
2951
|
-
// and that these were the only /media requests that were sent
|
|
2952
|
-
assert.calledTwice(locusMediaRequestStub);
|
|
2953
|
-
});
|
|
2954
|
-
|
|
2955
|
-
it('addMedia() works correctly when media is disabled with tracks to publish', async () => {
|
|
2956
|
-
await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}, audioEnabled: false});
|
|
2957
|
-
await simulateRoapOffer();
|
|
2958
|
-
await simulateRoapOk();
|
|
2959
|
-
|
|
2960
|
-
// check RoapMediaConnection was created correctly
|
|
2961
|
-
checkMediaConnectionCreated({
|
|
2962
|
-
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
2963
|
-
localStreams: {
|
|
2964
|
-
audio: fakeMicrophoneStream,
|
|
2965
|
-
video: undefined,
|
|
2966
|
-
screenShareVideo: undefined,
|
|
2967
|
-
screenShareAudio: undefined,
|
|
2968
|
-
},
|
|
2969
|
-
direction: {
|
|
2970
|
-
audio: 'inactive',
|
|
2971
|
-
video: 'sendrecv',
|
|
2972
|
-
screenShare: 'recvonly',
|
|
2973
|
-
},
|
|
2974
|
-
remoteQualityLevel: 'HIGH',
|
|
2975
|
-
expectedDebugId,
|
|
2976
|
-
meetingId: meeting.id
|
|
3070
|
+
// and that these were the only /media requests that were sent
|
|
3071
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
2977
3072
|
});
|
|
2978
3073
|
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
3074
|
+
it('addMedia() works correctly when media is disabled with tracks to publish', async () => {
|
|
3075
|
+
await meeting.addMedia({
|
|
3076
|
+
localStreams: {microphone: fakeMicrophoneStream},
|
|
3077
|
+
audioEnabled: false,
|
|
3078
|
+
});
|
|
3079
|
+
await simulateRoapOffer();
|
|
3080
|
+
await simulateRoapOk();
|
|
2983
3081
|
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
3082
|
+
// check RoapMediaConnection was created correctly
|
|
3083
|
+
checkMediaConnectionCreated({
|
|
3084
|
+
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3085
|
+
localStreams: {
|
|
3086
|
+
audio: fakeMicrophoneStream,
|
|
3087
|
+
video: undefined,
|
|
3088
|
+
screenShareVideo: undefined,
|
|
3089
|
+
screenShareAudio: undefined,
|
|
3090
|
+
},
|
|
3091
|
+
direction: {
|
|
3092
|
+
audio: 'inactive',
|
|
3093
|
+
video: 'sendrecv',
|
|
3094
|
+
screenShare: 'recvonly',
|
|
3095
|
+
},
|
|
3096
|
+
remoteQualityLevel: 'HIGH',
|
|
3097
|
+
expectedDebugId,
|
|
3098
|
+
meetingId: meeting.id,
|
|
3099
|
+
});
|
|
2987
3100
|
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
3101
|
+
// and SDP offer was sent with the right audioMuted/videoMuted values
|
|
3102
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3103
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3104
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
2992
3105
|
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
2996
|
-
localStreams: {
|
|
2997
|
-
audio: undefined,
|
|
2998
|
-
video: undefined,
|
|
2999
|
-
screenShareVideo: undefined,
|
|
3000
|
-
screenShareAudio: undefined,
|
|
3001
|
-
},
|
|
3002
|
-
direction: {
|
|
3003
|
-
audio: 'inactive',
|
|
3004
|
-
video: 'sendrecv',
|
|
3005
|
-
screenShare: 'recvonly',
|
|
3006
|
-
},
|
|
3007
|
-
remoteQualityLevel: 'HIGH',
|
|
3008
|
-
expectedDebugId,
|
|
3009
|
-
meetingId: meeting.id
|
|
3106
|
+
// and that these were the only /media requests that were sent
|
|
3107
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3010
3108
|
});
|
|
3011
3109
|
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
// and that these were the only /media requests that were sent
|
|
3018
|
-
assert.calledTwice(locusMediaRequestStub);
|
|
3019
|
-
});
|
|
3110
|
+
it('addMedia() works correctly when media is disabled with no tracks to publish', async () => {
|
|
3111
|
+
await meeting.addMedia({audioEnabled: false});
|
|
3112
|
+
await simulateRoapOffer();
|
|
3113
|
+
await simulateRoapOk();
|
|
3020
3114
|
|
|
3115
|
+
// check RoapMediaConnection was created correctly
|
|
3116
|
+
checkMediaConnectionCreated({
|
|
3117
|
+
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3118
|
+
localStreams: {
|
|
3119
|
+
audio: undefined,
|
|
3120
|
+
video: undefined,
|
|
3121
|
+
screenShareVideo: undefined,
|
|
3122
|
+
screenShareAudio: undefined,
|
|
3123
|
+
},
|
|
3124
|
+
direction: {
|
|
3125
|
+
audio: 'inactive',
|
|
3126
|
+
video: 'sendrecv',
|
|
3127
|
+
screenShare: 'recvonly',
|
|
3128
|
+
},
|
|
3129
|
+
remoteQualityLevel: 'HIGH',
|
|
3130
|
+
expectedDebugId,
|
|
3131
|
+
meetingId: meeting.id,
|
|
3132
|
+
});
|
|
3021
3133
|
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3134
|
+
// and SDP offer was sent with the right audioMuted/videoMuted values
|
|
3135
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3136
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3137
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
3026
3138
|
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3030
|
-
localStreams: {
|
|
3031
|
-
audio: undefined,
|
|
3032
|
-
video: undefined,
|
|
3033
|
-
screenShareVideo: undefined,
|
|
3034
|
-
screenShareAudio: undefined,
|
|
3035
|
-
},
|
|
3036
|
-
direction: {
|
|
3037
|
-
audio: 'sendrecv',
|
|
3038
|
-
video: 'inactive',
|
|
3039
|
-
screenShare: 'recvonly',
|
|
3040
|
-
},
|
|
3041
|
-
remoteQualityLevel: 'HIGH',
|
|
3042
|
-
expectedDebugId,
|
|
3043
|
-
meetingId: meeting.id
|
|
3139
|
+
// and that these were the only /media requests that were sent
|
|
3140
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3044
3141
|
});
|
|
3045
3142
|
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
// and that these were the only /media requests that were sent
|
|
3052
|
-
assert.calledTwice(locusMediaRequestStub);
|
|
3053
|
-
});
|
|
3143
|
+
it('addMedia() works correctly when video is disabled with no tracks to publish', async () => {
|
|
3144
|
+
await meeting.addMedia({videoEnabled: false});
|
|
3145
|
+
await simulateRoapOffer();
|
|
3146
|
+
await simulateRoapOk();
|
|
3054
3147
|
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3148
|
+
// check RoapMediaConnection was created correctly
|
|
3149
|
+
checkMediaConnectionCreated({
|
|
3150
|
+
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3151
|
+
localStreams: {
|
|
3152
|
+
audio: undefined,
|
|
3153
|
+
video: undefined,
|
|
3154
|
+
screenShareVideo: undefined,
|
|
3155
|
+
screenShareAudio: undefined,
|
|
3156
|
+
},
|
|
3157
|
+
direction: {
|
|
3158
|
+
audio: 'sendrecv',
|
|
3159
|
+
video: 'inactive',
|
|
3160
|
+
screenShare: 'recvonly',
|
|
3161
|
+
},
|
|
3162
|
+
remoteQualityLevel: 'HIGH',
|
|
3163
|
+
expectedDebugId,
|
|
3164
|
+
meetingId: meeting.id,
|
|
3165
|
+
});
|
|
3059
3166
|
|
|
3167
|
+
// and SDP offer was sent with the right audioMuted/videoMuted values
|
|
3168
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3169
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3170
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
3060
3171
|
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3064
|
-
localStreams: {
|
|
3065
|
-
audio: undefined,
|
|
3066
|
-
video: undefined,
|
|
3067
|
-
screenShareVideo: undefined,
|
|
3068
|
-
screenShareAudio: undefined,
|
|
3069
|
-
},
|
|
3070
|
-
direction: {
|
|
3071
|
-
audio: 'sendrecv',
|
|
3072
|
-
video: 'sendrecv',
|
|
3073
|
-
screenShare: 'inactive',
|
|
3074
|
-
},
|
|
3075
|
-
remoteQualityLevel: 'HIGH',
|
|
3076
|
-
expectedDebugId,
|
|
3077
|
-
meetingId: meeting.id
|
|
3172
|
+
// and that these were the only /media requests that were sent
|
|
3173
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3078
3174
|
});
|
|
3079
3175
|
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3176
|
+
it('addMedia() works correctly when screen share is disabled with no tracks to publish', async () => {
|
|
3177
|
+
await meeting.addMedia({shareAudioEnabled: false, shareVideoEnabled: false});
|
|
3178
|
+
await simulateRoapOffer();
|
|
3179
|
+
await simulateRoapOk();
|
|
3084
3180
|
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3181
|
+
// check RoapMediaConnection was created correctly
|
|
3182
|
+
checkMediaConnectionCreated({
|
|
3183
|
+
mediaConnectionConfig: expectedMediaConnectionConfig,
|
|
3184
|
+
localStreams: {
|
|
3185
|
+
audio: undefined,
|
|
3186
|
+
video: undefined,
|
|
3187
|
+
screenShareVideo: undefined,
|
|
3188
|
+
screenShareAudio: undefined,
|
|
3189
|
+
},
|
|
3190
|
+
direction: {
|
|
3191
|
+
audio: 'sendrecv',
|
|
3192
|
+
video: 'sendrecv',
|
|
3193
|
+
screenShare: 'inactive',
|
|
3194
|
+
},
|
|
3195
|
+
remoteQualityLevel: 'HIGH',
|
|
3196
|
+
expectedDebugId,
|
|
3197
|
+
meetingId: meeting.id,
|
|
3198
|
+
});
|
|
3088
3199
|
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
{
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3200
|
+
// and SDP offer was sent with the right audioMuted/videoMuted values
|
|
3201
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3202
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3203
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
3204
|
+
|
|
3205
|
+
// and that these were the only /media requests that were sent
|
|
3206
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3207
|
+
});
|
|
3208
|
+
|
|
3209
|
+
describe('publishStreams()/unpublishStreams() calls', () => {
|
|
3210
|
+
[
|
|
3211
|
+
{mediaEnabled: true, expected: {direction: 'sendrecv', localMuteSentValue: false}},
|
|
3212
|
+
{
|
|
3213
|
+
mediaEnabled: false,
|
|
3214
|
+
expected: {direction: 'inactive', localMuteSentValue: undefined},
|
|
3215
|
+
},
|
|
3216
|
+
].forEach(({mediaEnabled, expected}) => {
|
|
3217
|
+
it(`first publishStreams() call while media is ${
|
|
3218
|
+
mediaEnabled ? 'enabled' : 'disabled'
|
|
3219
|
+
}`, async () => {
|
|
3096
3220
|
await meeting.addMedia({audioEnabled: mediaEnabled});
|
|
3097
3221
|
await simulateRoapOffer();
|
|
3098
3222
|
await simulateRoapOk();
|
|
@@ -3114,10 +3238,18 @@ describe('plugin-meetings', () => {
|
|
|
3114
3238
|
}
|
|
3115
3239
|
|
|
3116
3240
|
if (isMultistream) {
|
|
3117
|
-
assert.calledOnceWithExactly(
|
|
3241
|
+
assert.calledOnceWithExactly(
|
|
3242
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream,
|
|
3243
|
+
fakeMicrophoneStream
|
|
3244
|
+
);
|
|
3118
3245
|
} else {
|
|
3119
3246
|
assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
|
|
3120
|
-
localTracks: {
|
|
3247
|
+
localTracks: {
|
|
3248
|
+
audio: fakeMicrophoneStream.outputStream.getTracks()[0],
|
|
3249
|
+
video: null,
|
|
3250
|
+
screenShareVideo: null,
|
|
3251
|
+
screenShareAudio: null,
|
|
3252
|
+
},
|
|
3121
3253
|
direction: {
|
|
3122
3254
|
audio: expected.direction,
|
|
3123
3255
|
video: 'sendrecv',
|
|
@@ -3128,7 +3260,9 @@ describe('plugin-meetings', () => {
|
|
|
3128
3260
|
}
|
|
3129
3261
|
});
|
|
3130
3262
|
|
|
3131
|
-
it(`second publishStreams() call while media is ${
|
|
3263
|
+
it(`second publishStreams() call while media is ${
|
|
3264
|
+
mediaEnabled ? 'enabled' : 'disabled'
|
|
3265
|
+
}`, async () => {
|
|
3132
3266
|
await meeting.addMedia({audioEnabled: mediaEnabled});
|
|
3133
3267
|
await simulateRoapOffer();
|
|
3134
3268
|
await simulateRoapOk();
|
|
@@ -3145,22 +3279,32 @@ describe('plugin-meetings', () => {
|
|
|
3145
3279
|
setMuted: sinon.stub(),
|
|
3146
3280
|
outputStream: {
|
|
3147
3281
|
getTracks: () => {
|
|
3148
|
-
return [
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3282
|
+
return [
|
|
3283
|
+
{
|
|
3284
|
+
id: 'fake mic 2',
|
|
3285
|
+
},
|
|
3286
|
+
];
|
|
3287
|
+
},
|
|
3288
|
+
},
|
|
3289
|
+
};
|
|
3154
3290
|
|
|
3155
3291
|
await meeting.publishStreams({microphone: fakeMicrophoneStream2});
|
|
3156
3292
|
await stableState();
|
|
3157
3293
|
|
|
3158
3294
|
// only the roap media connection should be updated
|
|
3159
3295
|
if (isMultistream) {
|
|
3160
|
-
assert.calledOnceWithExactly(
|
|
3296
|
+
assert.calledOnceWithExactly(
|
|
3297
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).publishStream,
|
|
3298
|
+
fakeMicrophoneStream2
|
|
3299
|
+
);
|
|
3161
3300
|
} else {
|
|
3162
3301
|
assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
|
|
3163
|
-
localTracks: {
|
|
3302
|
+
localTracks: {
|
|
3303
|
+
audio: fakeMicrophoneStream2.outputStream.getTracks()[0],
|
|
3304
|
+
video: null,
|
|
3305
|
+
screenShareVideo: null,
|
|
3306
|
+
screenShareAudio: null,
|
|
3307
|
+
},
|
|
3164
3308
|
direction: {
|
|
3165
3309
|
audio: expected.direction,
|
|
3166
3310
|
video: 'sendrecv',
|
|
@@ -3174,7 +3318,9 @@ describe('plugin-meetings', () => {
|
|
|
3174
3318
|
assert.notCalled(locusMediaRequestStub);
|
|
3175
3319
|
});
|
|
3176
3320
|
|
|
3177
|
-
it(`unpublishStreams() call while media is ${
|
|
3321
|
+
it(`unpublishStreams() call while media is ${
|
|
3322
|
+
mediaEnabled ? 'enabled' : 'disabled'
|
|
3323
|
+
}`, async () => {
|
|
3178
3324
|
await meeting.addMedia({audioEnabled: mediaEnabled});
|
|
3179
3325
|
await simulateRoapOffer();
|
|
3180
3326
|
await simulateRoapOk();
|
|
@@ -3188,10 +3334,17 @@ describe('plugin-meetings', () => {
|
|
|
3188
3334
|
|
|
3189
3335
|
// the roap media connection should be updated
|
|
3190
3336
|
if (isMultistream) {
|
|
3191
|
-
assert.calledOnce(
|
|
3337
|
+
assert.calledOnce(
|
|
3338
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).unpublishStream
|
|
3339
|
+
);
|
|
3192
3340
|
} else {
|
|
3193
3341
|
assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
|
|
3194
|
-
localTracks: {
|
|
3342
|
+
localTracks: {
|
|
3343
|
+
audio: null,
|
|
3344
|
+
video: null,
|
|
3345
|
+
screenShareVideo: null,
|
|
3346
|
+
screenShareAudio: null,
|
|
3347
|
+
},
|
|
3195
3348
|
direction: {
|
|
3196
3349
|
audio: expected.direction,
|
|
3197
3350
|
video: 'sendrecv',
|
|
@@ -3214,180 +3367,194 @@ describe('plugin-meetings', () => {
|
|
|
3214
3367
|
}
|
|
3215
3368
|
});
|
|
3216
3369
|
});
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
describe('updateMedia()', () => {
|
|
3370
|
+
});
|
|
3220
3371
|
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3372
|
+
describe('updateMedia()', () => {
|
|
3373
|
+
const addMedia = async (enableMedia, stream) => {
|
|
3374
|
+
await meeting.addMedia({
|
|
3375
|
+
audioEnabled: enableMedia,
|
|
3376
|
+
localStreams: {microphone: stream},
|
|
3377
|
+
});
|
|
3378
|
+
await simulateRoapOffer();
|
|
3379
|
+
await simulateRoapOk();
|
|
3225
3380
|
|
|
3226
|
-
|
|
3227
|
-
|
|
3381
|
+
resetHistory();
|
|
3382
|
+
};
|
|
3228
3383
|
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3384
|
+
const checkAudioEnabled = (expectedStream, expectedDirection) => {
|
|
3385
|
+
if (isMultistream) {
|
|
3386
|
+
assert.equal(
|
|
3387
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).active,
|
|
3388
|
+
expectedDirection !== 'inactive'
|
|
3389
|
+
);
|
|
3390
|
+
} else {
|
|
3391
|
+
assert.calledOnceWithExactly(fakeRoapMediaConnection.update, {
|
|
3392
|
+
localTracks: {
|
|
3393
|
+
audio: expectedStream?.outputStream.getTracks()[0] ?? null,
|
|
3394
|
+
video: null,
|
|
3395
|
+
screenShareVideo: null,
|
|
3396
|
+
screenShareAudio: null,
|
|
3397
|
+
},
|
|
3398
|
+
direction: {
|
|
3399
|
+
audio: expectedDirection,
|
|
3400
|
+
video: 'sendrecv',
|
|
3401
|
+
screenShareVideo: 'recvonly',
|
|
3402
|
+
},
|
|
3403
|
+
remoteQualityLevel: 'HIGH',
|
|
3404
|
+
});
|
|
3405
|
+
}
|
|
3406
|
+
};
|
|
3244
3407
|
|
|
3245
|
-
|
|
3246
|
-
|
|
3408
|
+
it('updateMedia() disables media when nothing is published', async () => {
|
|
3409
|
+
await addMedia(true);
|
|
3247
3410
|
|
|
3248
|
-
|
|
3411
|
+
await meeting.updateMedia({audioEnabled: false});
|
|
3249
3412
|
|
|
3250
|
-
|
|
3251
|
-
|
|
3413
|
+
// the roap media connection should be updated
|
|
3414
|
+
checkAudioEnabled(null, 'inactive');
|
|
3252
3415
|
|
|
3253
|
-
|
|
3254
|
-
|
|
3416
|
+
// and that would trigger a new offer so we simulate it happening
|
|
3417
|
+
await simulateRoapOffer();
|
|
3255
3418
|
|
|
3256
|
-
|
|
3257
|
-
|
|
3419
|
+
// check SDP offer was sent with the right audioMuted/videoMuted values
|
|
3420
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3258
3421
|
|
|
3259
|
-
|
|
3260
|
-
|
|
3422
|
+
// simulate OK being sent in response to remote answer being received
|
|
3423
|
+
await simulateRoapOk();
|
|
3261
3424
|
|
|
3262
|
-
|
|
3263
|
-
|
|
3425
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3426
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
3264
3427
|
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3428
|
+
// and no other local mute requests were sent to Locus
|
|
3429
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3430
|
+
});
|
|
3268
3431
|
|
|
3269
|
-
|
|
3270
|
-
|
|
3432
|
+
it('updateMedia() enables media when nothing is published', async () => {
|
|
3433
|
+
await addMedia(false);
|
|
3271
3434
|
|
|
3272
|
-
|
|
3435
|
+
await meeting.updateMedia({audioEnabled: true});
|
|
3273
3436
|
|
|
3274
|
-
|
|
3275
|
-
|
|
3437
|
+
// the roap media connection should be updated
|
|
3438
|
+
checkAudioEnabled(null, 'sendrecv');
|
|
3276
3439
|
|
|
3277
|
-
|
|
3278
|
-
|
|
3440
|
+
// and that would trigger a new offer so we simulate it happening
|
|
3441
|
+
await simulateRoapOffer();
|
|
3279
3442
|
|
|
3280
|
-
|
|
3281
|
-
|
|
3443
|
+
// check SDP offer was sent with the right audioMuted/videoMuted values
|
|
3444
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3282
3445
|
|
|
3283
|
-
|
|
3284
|
-
|
|
3446
|
+
// simulate OK being sent in response to remote answer being received
|
|
3447
|
+
await simulateRoapOk();
|
|
3285
3448
|
|
|
3286
|
-
|
|
3287
|
-
|
|
3449
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3450
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
3288
3451
|
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3452
|
+
// and no other local mute requests were sent to Locus
|
|
3453
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3454
|
+
});
|
|
3292
3455
|
|
|
3293
|
-
|
|
3294
|
-
|
|
3456
|
+
it('updateMedia() disables media when stream is published', async () => {
|
|
3457
|
+
await addMedia(true, fakeMicrophoneStream);
|
|
3295
3458
|
|
|
3296
|
-
|
|
3297
|
-
|
|
3459
|
+
await meeting.updateMedia({audioEnabled: false});
|
|
3460
|
+
await stableState();
|
|
3298
3461
|
|
|
3299
|
-
|
|
3300
|
-
|
|
3462
|
+
// the roap media connection should be updated
|
|
3463
|
+
checkAudioEnabled(fakeMicrophoneStream, 'inactive');
|
|
3301
3464
|
|
|
3302
|
-
|
|
3465
|
+
checkLocalMuteSentToLocus({audioMuted: true, videoMuted: true});
|
|
3303
3466
|
|
|
3304
|
-
|
|
3467
|
+
locusMediaRequestStub.resetHistory();
|
|
3305
3468
|
|
|
3306
|
-
|
|
3307
|
-
|
|
3469
|
+
// and that would trigger a new offer so we simulate it happening
|
|
3470
|
+
await simulateRoapOffer();
|
|
3308
3471
|
|
|
3309
|
-
|
|
3310
|
-
|
|
3472
|
+
// check SDP offer was sent with the right audioMuted/videoMuted values
|
|
3473
|
+
checkSdpOfferSent({audioMuted: true, videoMuted: true});
|
|
3311
3474
|
|
|
3312
|
-
|
|
3313
|
-
|
|
3475
|
+
// simulate OK being sent in response to remote answer being received
|
|
3476
|
+
await simulateRoapOk();
|
|
3314
3477
|
|
|
3315
|
-
|
|
3316
|
-
|
|
3478
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3479
|
+
checkOkSent({audioMuted: true, videoMuted: true});
|
|
3317
3480
|
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3481
|
+
// and no other local mute requests were sent to Locus
|
|
3482
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3483
|
+
});
|
|
3321
3484
|
|
|
3322
|
-
|
|
3323
|
-
|
|
3485
|
+
it('updateMedia() enables media when stream is published', async () => {
|
|
3486
|
+
await addMedia(false, fakeMicrophoneStream);
|
|
3324
3487
|
|
|
3325
|
-
|
|
3326
|
-
|
|
3488
|
+
await meeting.updateMedia({audioEnabled: true});
|
|
3489
|
+
await stableState();
|
|
3327
3490
|
|
|
3328
|
-
|
|
3329
|
-
|
|
3491
|
+
// the roap media connection should be updated
|
|
3492
|
+
checkAudioEnabled(fakeMicrophoneStream, 'sendrecv');
|
|
3330
3493
|
|
|
3331
|
-
|
|
3494
|
+
checkLocalMuteSentToLocus({audioMuted: false, videoMuted: true});
|
|
3332
3495
|
|
|
3333
|
-
|
|
3496
|
+
locusMediaRequestStub.resetHistory();
|
|
3334
3497
|
|
|
3335
|
-
|
|
3336
|
-
|
|
3498
|
+
// and that would trigger a new offer so we simulate it happening
|
|
3499
|
+
await simulateRoapOffer();
|
|
3337
3500
|
|
|
3338
|
-
|
|
3339
|
-
|
|
3501
|
+
// check SDP offer was sent with the right audioMuted/videoMuted values
|
|
3502
|
+
checkSdpOfferSent({audioMuted: false, videoMuted: true});
|
|
3340
3503
|
|
|
3341
|
-
|
|
3342
|
-
|
|
3504
|
+
// simulate OK being sent in response to remote answer being received
|
|
3505
|
+
await simulateRoapOk();
|
|
3343
3506
|
|
|
3344
|
-
|
|
3345
|
-
|
|
3507
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3508
|
+
checkOkSent({audioMuted: false, videoMuted: true});
|
|
3346
3509
|
|
|
3347
|
-
|
|
3348
|
-
|
|
3510
|
+
// and no other local mute requests were sent to Locus
|
|
3511
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3512
|
+
});
|
|
3349
3513
|
});
|
|
3350
|
-
});
|
|
3351
3514
|
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3515
|
+
[
|
|
3516
|
+
{mute: true, title: 'muting a track before confluence is created'},
|
|
3517
|
+
{mute: false, title: 'unmuting a track before confluence is created'},
|
|
3518
|
+
].forEach(({mute, title}) =>
|
|
3519
|
+
it(title, async () => {
|
|
3520
|
+
// initialize the microphone mute state to opposite of what we do in the test
|
|
3521
|
+
fakeMicrophoneStream.muted = !mute;
|
|
3359
3522
|
|
|
3360
|
-
|
|
3361
|
-
|
|
3523
|
+
await meeting.addMedia({localStreams: {microphone: fakeMicrophoneStream}});
|
|
3524
|
+
await stableState();
|
|
3362
3525
|
|
|
3363
|
-
|
|
3526
|
+
resetHistory();
|
|
3364
3527
|
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3528
|
+
assert.equal(
|
|
3529
|
+
fakeMicrophoneStream.on.getCall(0).args[0],
|
|
3530
|
+
StreamEventNames.MuteStateChange
|
|
3531
|
+
);
|
|
3532
|
+
const mutedListener = fakeMicrophoneStream.on.getCall(0).args[1];
|
|
3533
|
+
// simulate track being muted
|
|
3534
|
+
mutedListener(mute);
|
|
3369
3535
|
|
|
3370
|
-
|
|
3536
|
+
await stableState();
|
|
3371
3537
|
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3538
|
+
// nothing should happen
|
|
3539
|
+
assert.notCalled(locusMediaRequestStub);
|
|
3540
|
+
assert.notCalled(fakeRoapMediaConnection.update);
|
|
3375
3541
|
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3542
|
+
// now simulate roap offer and ok
|
|
3543
|
+
await simulateRoapOffer();
|
|
3544
|
+
await simulateRoapOk();
|
|
3379
3545
|
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3546
|
+
// it should be sent with the right mute status
|
|
3547
|
+
checkSdpOfferSent({audioMuted: mute, videoMuted: true});
|
|
3548
|
+
// check OK was sent with the right audioMuted/videoMuted values
|
|
3549
|
+
checkOkSent({audioMuted: mute, videoMuted: true});
|
|
3384
3550
|
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3551
|
+
// nothing else should happen
|
|
3552
|
+
assert.calledTwice(locusMediaRequestStub);
|
|
3553
|
+
assert.notCalled(fakeRoapMediaConnection.update);
|
|
3554
|
+
})
|
|
3555
|
+
);
|
|
3556
|
+
})
|
|
3557
|
+
);
|
|
3391
3558
|
|
|
3392
3559
|
describe('#acknowledge', () => {
|
|
3393
3560
|
it('should have #acknowledge', () => {
|
|
@@ -3684,13 +3851,13 @@ describe('plugin-meetings', () => {
|
|
|
3684
3851
|
outputStream: {
|
|
3685
3852
|
getTracks: () => {
|
|
3686
3853
|
return [{id: 'fake underlying track'}];
|
|
3687
|
-
}
|
|
3688
|
-
}
|
|
3854
|
+
},
|
|
3855
|
+
},
|
|
3689
3856
|
});
|
|
3690
3857
|
beforeEach(() => {
|
|
3691
3858
|
sandbox = sinon.createSandbox();
|
|
3692
|
-
meeting.audio = {
|
|
3693
|
-
meeting.video = {
|
|
3859
|
+
meeting.audio = {enable: sinon.stub()};
|
|
3860
|
+
meeting.video = {enable: sinon.stub()};
|
|
3694
3861
|
meeting.mediaProperties.audioStream = createFakeLocalStream();
|
|
3695
3862
|
meeting.mediaProperties.videoStream = createFakeLocalStream();
|
|
3696
3863
|
meeting.mediaProperties.shareVideoStream = createFakeLocalStream();
|
|
@@ -3702,12 +3869,15 @@ describe('plugin-meetings', () => {
|
|
|
3702
3869
|
receiveAudio: true,
|
|
3703
3870
|
receiveVideo: true,
|
|
3704
3871
|
receiveShare: true,
|
|
3705
|
-
}
|
|
3872
|
+
};
|
|
3706
3873
|
const fakeMultistreamRoapMediaConnection = {
|
|
3707
|
-
createSendSlot: () => {}
|
|
3874
|
+
createSendSlot: () => {},
|
|
3708
3875
|
};
|
|
3709
|
-
sinon.stub(fakeMultistreamRoapMediaConnection,'createSendSlot').returns({active: true});
|
|
3710
|
-
meeting.sendSlotManager.createSlot(
|
|
3876
|
+
sinon.stub(fakeMultistreamRoapMediaConnection, 'createSendSlot').returns({active: true});
|
|
3877
|
+
meeting.sendSlotManager.createSlot(
|
|
3878
|
+
fakeMultistreamRoapMediaConnection,
|
|
3879
|
+
MediaType.AudioMain
|
|
3880
|
+
);
|
|
3711
3881
|
});
|
|
3712
3882
|
|
|
3713
3883
|
afterEach(() => {
|
|
@@ -3764,23 +3934,22 @@ describe('plugin-meetings', () => {
|
|
|
3764
3934
|
// and check that update is called with the original args
|
|
3765
3935
|
assert.calledOnce(meeting.mediaProperties.webrtcMediaConnection.update);
|
|
3766
3936
|
|
|
3767
|
-
assert.calledWith(
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
);
|
|
3937
|
+
assert.calledWith(meeting.mediaProperties.webrtcMediaConnection.update, {
|
|
3938
|
+
localTracks: {
|
|
3939
|
+
audio: meeting.mediaProperties.audioStream.outputStream.getTracks()[0],
|
|
3940
|
+
video: meeting.mediaProperties.videoStream.outputStream.getTracks()[0],
|
|
3941
|
+
screenShareVideo:
|
|
3942
|
+
meeting.mediaProperties.shareVideoStream.outputStream.getTracks()[0],
|
|
3943
|
+
screenShareAudio:
|
|
3944
|
+
meeting.mediaProperties.shareVideoStream.outputStream.getTracks()[0],
|
|
3945
|
+
},
|
|
3946
|
+
direction: {
|
|
3947
|
+
audio: 'inactive',
|
|
3948
|
+
video: 'inactive',
|
|
3949
|
+
screenShareVideo: 'sendrecv',
|
|
3950
|
+
},
|
|
3951
|
+
remoteQualityLevel: 'HIGH',
|
|
3952
|
+
});
|
|
3784
3953
|
assert.isTrue(myPromiseResolved);
|
|
3785
3954
|
});
|
|
3786
3955
|
});
|
|
@@ -3798,15 +3967,13 @@ describe('plugin-meetings', () => {
|
|
|
3798
3967
|
receiveVideo: true,
|
|
3799
3968
|
};
|
|
3800
3969
|
meeting.mediaProperties.mediaDirection = mediaDirection;
|
|
3801
|
-
meeting.mediaProperties.remoteVideoStream = sinon
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
}
|
|
3809
|
-
});
|
|
3970
|
+
meeting.mediaProperties.remoteVideoStream = sinon.stub().returns({
|
|
3971
|
+
outputStream: {
|
|
3972
|
+
getTracks: () => {
|
|
3973
|
+
id: 'some mock id';
|
|
3974
|
+
},
|
|
3975
|
+
},
|
|
3976
|
+
});
|
|
3810
3977
|
|
|
3811
3978
|
meeting.meetingRequest.changeVideoLayoutDebounced = sinon
|
|
3812
3979
|
.stub()
|
|
@@ -3883,7 +4050,9 @@ describe('plugin-meetings', () => {
|
|
|
3883
4050
|
});
|
|
3884
4051
|
|
|
3885
4052
|
meeting.mediaProperties.mediaDirection.receiveShare = true;
|
|
3886
|
-
meeting.mediaProperties.remoteShareStream = sinon
|
|
4053
|
+
meeting.mediaProperties.remoteShareStream = sinon
|
|
4054
|
+
.stub()
|
|
4055
|
+
.returns({mockTrack: 'mockTrack'});
|
|
3887
4056
|
|
|
3888
4057
|
// now call it again with just content
|
|
3889
4058
|
await meeting.changeVideoLayout(layoutTypeSingle, {content: {width: 500, height: 600}});
|
|
@@ -3952,7 +4121,9 @@ describe('plugin-meetings', () => {
|
|
|
3952
4121
|
|
|
3953
4122
|
it('does not call changeVideoLayoutDebounced if renderInfo content changes only very slightly', async () => {
|
|
3954
4123
|
meeting.mediaProperties.mediaDirection.receiveShare = true;
|
|
3955
|
-
meeting.mediaProperties.remoteShareStream = sinon
|
|
4124
|
+
meeting.mediaProperties.remoteShareStream = sinon
|
|
4125
|
+
.stub()
|
|
4126
|
+
.returns({mockTrack: 'mockTrack'});
|
|
3956
4127
|
|
|
3957
4128
|
await meeting.changeVideoLayout(layoutTypeSingle, {
|
|
3958
4129
|
main: {width: 500, height: 510},
|
|
@@ -3992,7 +4163,9 @@ describe('plugin-meetings', () => {
|
|
|
3992
4163
|
|
|
3993
4164
|
it('rounds the width and height values to nearest integers', async () => {
|
|
3994
4165
|
meeting.mediaProperties.mediaDirection.receiveShare = true;
|
|
3995
|
-
meeting.mediaProperties.remoteShareStream = sinon
|
|
4166
|
+
meeting.mediaProperties.remoteShareStream = sinon
|
|
4167
|
+
.stub()
|
|
4168
|
+
.returns({mockTrack: 'mockTrack'});
|
|
3996
4169
|
|
|
3997
4170
|
await meeting.changeVideoLayout(layoutTypeSingle, {
|
|
3998
4171
|
main: {width: 500.5, height: 510.09},
|
|
@@ -4258,11 +4431,7 @@ describe('plugin-meetings', () => {
|
|
|
4258
4431
|
FAKE_OPTIONS
|
|
4259
4432
|
);
|
|
4260
4433
|
|
|
4261
|
-
assert.calledWith(
|
|
4262
|
-
meeting.parseMeetingInfo,
|
|
4263
|
-
{body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL},
|
|
4264
|
-
FAKE_DESTINATION
|
|
4265
|
-
);
|
|
4434
|
+
assert.calledWith(meeting.parseMeetingInfo, FAKE_MEETING_INFO, FAKE_DESTINATION);
|
|
4266
4435
|
assert.deepEqual(meeting.meetingInfo, {
|
|
4267
4436
|
...FAKE_MEETING_INFO,
|
|
4268
4437
|
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
|
|
@@ -4315,12 +4484,8 @@ describe('plugin-meetings', () => {
|
|
|
4315
4484
|
{meetingId: meeting.id, sendCAevents: false}
|
|
4316
4485
|
);
|
|
4317
4486
|
|
|
4318
|
-
// parseMeeting info
|
|
4319
|
-
assert.calledWith(
|
|
4320
|
-
meeting.parseMeetingInfo,
|
|
4321
|
-
{body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL},
|
|
4322
|
-
FAKE_DESTINATION
|
|
4323
|
-
);
|
|
4487
|
+
// parseMeeting info
|
|
4488
|
+
assert.calledWith(meeting.parseMeetingInfo, FAKE_MEETING_INFO, FAKE_DESTINATION);
|
|
4324
4489
|
|
|
4325
4490
|
assert.deepEqual(meeting.meetingInfo, {
|
|
4326
4491
|
...FAKE_MEETING_INFO,
|
|
@@ -4456,7 +4621,7 @@ describe('plugin-meetings', () => {
|
|
|
4456
4621
|
await assert.isRejected(
|
|
4457
4622
|
meeting.fetchMeetingInfo({
|
|
4458
4623
|
password: 'aaa',
|
|
4459
|
-
sendCAevents: true
|
|
4624
|
+
sendCAevents: true,
|
|
4460
4625
|
}),
|
|
4461
4626
|
CaptchaError
|
|
4462
4627
|
);
|
|
@@ -4621,6 +4786,166 @@ describe('plugin-meetings', () => {
|
|
|
4621
4786
|
});
|
|
4622
4787
|
});
|
|
4623
4788
|
|
|
4789
|
+
describe('#injectMeetingInfo', () => {
|
|
4790
|
+
const FAKE_PASSWORD = '123456';
|
|
4791
|
+
const FAKE_CAPTCHA_CODE = '654321';
|
|
4792
|
+
const FAKE_DESTINATION = 'something@somecompany.com';
|
|
4793
|
+
const FAKE_TYPE = _SIP_URI_;
|
|
4794
|
+
const FAKE_INSTALLED_ORG_ID = '123456';
|
|
4795
|
+
const FAKE_MEETING_INFO_LOOKUP_URL = 'meetingLookupUrl';
|
|
4796
|
+
|
|
4797
|
+
const FAKE_SDK_CAPTCHA_INFO = {};
|
|
4798
|
+
const FAKE_MEETING_INFO = {
|
|
4799
|
+
conversationUrl: 'some_convo_url',
|
|
4800
|
+
locusUrl: 'some_locus_url',
|
|
4801
|
+
sipUrl: 'some_sip_url', // or sipMeetingUri
|
|
4802
|
+
meetingNumber: '123456', // this.config.experimental.enableUnifiedMeetings
|
|
4803
|
+
hostId: 'some_host_id', // this.owner;
|
|
4804
|
+
};
|
|
4805
|
+
|
|
4806
|
+
[
|
|
4807
|
+
{
|
|
4808
|
+
input: {
|
|
4809
|
+
meetingInfo: FAKE_MEETING_INFO,
|
|
4810
|
+
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
|
|
4811
|
+
},
|
|
4812
|
+
expected: {
|
|
4813
|
+
meetingInfo: {
|
|
4814
|
+
...FAKE_MEETING_INFO,
|
|
4815
|
+
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
|
|
4816
|
+
},
|
|
4817
|
+
},
|
|
4818
|
+
},
|
|
4819
|
+
{
|
|
4820
|
+
input: {
|
|
4821
|
+
meetingInfo: undefined,
|
|
4822
|
+
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
|
|
4823
|
+
},
|
|
4824
|
+
expected: {meetingInfo: null},
|
|
4825
|
+
},
|
|
4826
|
+
,
|
|
4827
|
+
{
|
|
4828
|
+
input: {
|
|
4829
|
+
meetingInfo: FAKE_MEETING_INFO,
|
|
4830
|
+
meetingLookupUrl: undefined,
|
|
4831
|
+
},
|
|
4832
|
+
expected: {
|
|
4833
|
+
meetingInfo: {
|
|
4834
|
+
...FAKE_MEETING_INFO,
|
|
4835
|
+
meetingLookupUrl: undefined,
|
|
4836
|
+
},
|
|
4837
|
+
},
|
|
4838
|
+
},
|
|
4839
|
+
,
|
|
4840
|
+
{
|
|
4841
|
+
input: {
|
|
4842
|
+
meetingInfo: undefined,
|
|
4843
|
+
meetingLookupUrl: undefined,
|
|
4844
|
+
},
|
|
4845
|
+
expected: {meetingInfo: null},
|
|
4846
|
+
},
|
|
4847
|
+
].forEach(({input, expected}) => {
|
|
4848
|
+
it(`calls meetingInfoProvider with all the right parameters and parses the result when ${JSON.stringify(
|
|
4849
|
+
input
|
|
4850
|
+
)}`, async () => {
|
|
4851
|
+
meeting.requiredCaptcha = FAKE_SDK_CAPTCHA_INFO;
|
|
4852
|
+
meeting.destination = FAKE_DESTINATION;
|
|
4853
|
+
meeting.destinationType = FAKE_TYPE;
|
|
4854
|
+
meeting.config.installedOrgID = FAKE_INSTALLED_ORG_ID;
|
|
4855
|
+
meeting.parseMeetingInfo = sinon.stub().returns(undefined);
|
|
4856
|
+
meeting.updateMeetingActions = sinon.stub().returns(undefined);
|
|
4857
|
+
|
|
4858
|
+
await meeting.injectMeetingInfo(
|
|
4859
|
+
input.meetingInfo,
|
|
4860
|
+
{sendCAevents: true},
|
|
4861
|
+
input.meetingLookupUrl
|
|
4862
|
+
);
|
|
4863
|
+
|
|
4864
|
+
assert.calledWith(meeting.parseMeetingInfo, input.meetingInfo, FAKE_DESTINATION);
|
|
4865
|
+
assert.deepEqual(meeting.meetingInfo, expected.meetingInfo);
|
|
4866
|
+
assert.equal(meeting.passwordStatus, PASSWORD_STATUS.NOT_REQUIRED);
|
|
4867
|
+
assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
|
|
4868
|
+
assert.equal(meeting.requiredCaptcha, null);
|
|
4869
|
+
assert.calledThrice(TriggerProxy.trigger);
|
|
4870
|
+
assert.calledWith(
|
|
4871
|
+
TriggerProxy.trigger,
|
|
4872
|
+
meeting,
|
|
4873
|
+
{file: 'meetings', function: 'fetchMeetingInfo'},
|
|
4874
|
+
'meeting:meetingInfoAvailable'
|
|
4875
|
+
);
|
|
4876
|
+
assert.calledWith(meeting.updateMeetingActions);
|
|
4877
|
+
});
|
|
4878
|
+
});
|
|
4879
|
+
|
|
4880
|
+
it('fails if captchaCode is provided when captcha not needed', async () => {
|
|
4881
|
+
meeting.attrs.meetingInfoProvider = {
|
|
4882
|
+
fetchMeetingInfo: sinon.stub().resolves(),
|
|
4883
|
+
};
|
|
4884
|
+
meeting.requiredCaptcha = null;
|
|
4885
|
+
meeting.destination = FAKE_DESTINATION;
|
|
4886
|
+
meeting.destinationType = FAKE_TYPE;
|
|
4887
|
+
|
|
4888
|
+
await assert.isRejected(
|
|
4889
|
+
meeting.injectMeetingInfo(
|
|
4890
|
+
{},
|
|
4891
|
+
{
|
|
4892
|
+
captchaCode: FAKE_CAPTCHA_CODE,
|
|
4893
|
+
}
|
|
4894
|
+
),
|
|
4895
|
+
Error,
|
|
4896
|
+
'injectMeetingInfo() called with captchaCode when captcha was not required'
|
|
4897
|
+
);
|
|
4898
|
+
|
|
4899
|
+
assert.notCalled(meeting.attrs.meetingInfoProvider.fetchMeetingInfo);
|
|
4900
|
+
assert.calledTwice(TriggerProxy.trigger); //meetingInfoAvailable event not triggered
|
|
4901
|
+
assert.neverCalledWith(
|
|
4902
|
+
TriggerProxy.trigger,
|
|
4903
|
+
meeting,
|
|
4904
|
+
{file: 'meetings', function: 'fetchMeetingInfo'},
|
|
4905
|
+
'meeting:meetingInfoAvailable'
|
|
4906
|
+
);
|
|
4907
|
+
});
|
|
4908
|
+
|
|
4909
|
+
it('fails if password is provided when not required', async () => {
|
|
4910
|
+
meeting.attrs.meetingInfoProvider = {
|
|
4911
|
+
fetchMeetingInfo: sinon.stub().resolves(),
|
|
4912
|
+
};
|
|
4913
|
+
meeting.passwordStatus = PASSWORD_STATUS.NOT_REQUIRED;
|
|
4914
|
+
meeting.destination = FAKE_DESTINATION;
|
|
4915
|
+
meeting.destinationType = FAKE_TYPE;
|
|
4916
|
+
|
|
4917
|
+
await assert.isRejected(
|
|
4918
|
+
meeting.injectMeetingInfo(
|
|
4919
|
+
{},
|
|
4920
|
+
{
|
|
4921
|
+
password: FAKE_PASSWORD,
|
|
4922
|
+
}
|
|
4923
|
+
),
|
|
4924
|
+
Error,
|
|
4925
|
+
'injectMeetingInfo() called with password when password was not required'
|
|
4926
|
+
);
|
|
4927
|
+
|
|
4928
|
+
assert.notCalled(meeting.attrs.meetingInfoProvider.fetchMeetingInfo);
|
|
4929
|
+
assert.calledTwice(TriggerProxy.trigger); //meetingInfoAvailable event not triggered
|
|
4930
|
+
assert.neverCalledWith(
|
|
4931
|
+
TriggerProxy.trigger,
|
|
4932
|
+
meeting,
|
|
4933
|
+
{file: 'meetings', function: 'fetchMeetingInfo'},
|
|
4934
|
+
'meeting:meetingInfoAvailable'
|
|
4935
|
+
);
|
|
4936
|
+
});
|
|
4937
|
+
|
|
4938
|
+
it('should clean the fetch meeting info timeout', async () => {
|
|
4939
|
+
meeting.fetchMeetingInfoTimeoutId = 42; // pending delayed request
|
|
4940
|
+
|
|
4941
|
+
await meeting.injectMeetingInfo(FAKE_MEETING_INFO, {
|
|
4942
|
+
sendCAevents: true,
|
|
4943
|
+
});
|
|
4944
|
+
|
|
4945
|
+
assert.equal(meeting.fetchMeetingInfoTimeoutId, undefined);
|
|
4946
|
+
});
|
|
4947
|
+
});
|
|
4948
|
+
|
|
4624
4949
|
describe('#refreshPermissionToken', () => {
|
|
4625
4950
|
const FAKE_MEETING_INFO = {
|
|
4626
4951
|
conversationUrl: 'some_convo_url',
|
|
@@ -4641,9 +4966,9 @@ describe('plugin-meetings', () => {
|
|
|
4641
4966
|
meeting.destination = 'meeting-destination';
|
|
4642
4967
|
meeting.destinationType = 'meeting-destination-type';
|
|
4643
4968
|
meeting.updateMeetingActions = sinon.stub().returns(undefined);
|
|
4644
|
-
|
|
4969
|
+
|
|
4645
4970
|
meeting.meetingInfoExtraParams = {
|
|
4646
|
-
extraParam1: 'value1'
|
|
4971
|
+
extraParam1: 'value1',
|
|
4647
4972
|
};
|
|
4648
4973
|
meeting.attrs.meetingInfoProvider = {
|
|
4649
4974
|
fetchMeetingInfo: sinon
|
|
@@ -4678,7 +5003,7 @@ describe('plugin-meetings', () => {
|
|
|
4678
5003
|
);
|
|
4679
5004
|
assert.deepEqual(meeting.meetingInfo, {
|
|
4680
5005
|
...FAKE_MEETING_INFO,
|
|
4681
|
-
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL
|
|
5006
|
+
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
|
|
4682
5007
|
});
|
|
4683
5008
|
assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
|
|
4684
5009
|
assert.equal(meeting.requiredCaptcha, null);
|
|
@@ -4693,7 +5018,9 @@ describe('plugin-meetings', () => {
|
|
|
4693
5018
|
assert.calledWith(meeting.updateMeetingActions);
|
|
4694
5019
|
|
|
4695
5020
|
assert.calledWith(
|
|
4696
|
-
Metrics.sendBehavioralMetric,
|
|
5021
|
+
Metrics.sendBehavioralMetric,
|
|
5022
|
+
BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH,
|
|
5023
|
+
{
|
|
4697
5024
|
correlationId: meeting.correlationId,
|
|
4698
5025
|
timeLeft: FAKE_TIMESTAMPS.timeLeft,
|
|
4699
5026
|
expiryTime: FAKE_TIMESTAMPS.expiryTime,
|
|
@@ -4721,7 +5048,7 @@ describe('plugin-meetings', () => {
|
|
|
4721
5048
|
);
|
|
4722
5049
|
assert.deepEqual(meeting.meetingInfo, {
|
|
4723
5050
|
...FAKE_MEETING_INFO,
|
|
4724
|
-
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL
|
|
5051
|
+
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
|
|
4725
5052
|
});
|
|
4726
5053
|
assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
|
|
4727
5054
|
assert.equal(meeting.requiredCaptcha, null);
|
|
@@ -4736,7 +5063,9 @@ describe('plugin-meetings', () => {
|
|
|
4736
5063
|
assert.calledWith(meeting.updateMeetingActions);
|
|
4737
5064
|
|
|
4738
5065
|
assert.calledWith(
|
|
4739
|
-
Metrics.sendBehavioralMetric,
|
|
5066
|
+
Metrics.sendBehavioralMetric,
|
|
5067
|
+
BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH,
|
|
5068
|
+
{
|
|
4740
5069
|
correlationId: meeting.correlationId,
|
|
4741
5070
|
timeLeft: undefined,
|
|
4742
5071
|
expiryTime: undefined,
|
|
@@ -4767,13 +5096,13 @@ describe('plugin-meetings', () => {
|
|
|
4767
5096
|
'locus-id',
|
|
4768
5097
|
{
|
|
4769
5098
|
extraParam1: 'value1',
|
|
4770
|
-
permissionToken: FAKE_PERMISSION_TOKEN
|
|
5099
|
+
permissionToken: FAKE_PERMISSION_TOKEN,
|
|
4771
5100
|
},
|
|
4772
5101
|
{meetingId: meeting.id, sendCAevents: true}
|
|
4773
5102
|
);
|
|
4774
5103
|
assert.deepEqual(meeting.meetingInfo, {
|
|
4775
5104
|
...FAKE_MEETING_INFO,
|
|
4776
|
-
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL
|
|
5105
|
+
meetingLookupUrl: FAKE_MEETING_INFO_LOOKUP_URL,
|
|
4777
5106
|
});
|
|
4778
5107
|
assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.NONE);
|
|
4779
5108
|
assert.equal(meeting.requiredCaptcha, null);
|
|
@@ -4788,7 +5117,9 @@ describe('plugin-meetings', () => {
|
|
|
4788
5117
|
assert.calledWith(meeting.updateMeetingActions);
|
|
4789
5118
|
|
|
4790
5119
|
assert.calledWith(
|
|
4791
|
-
Metrics.sendBehavioralMetric,
|
|
5120
|
+
Metrics.sendBehavioralMetric,
|
|
5121
|
+
BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH,
|
|
5122
|
+
{
|
|
4792
5123
|
correlationId: meeting.correlationId,
|
|
4793
5124
|
timeLeft: FAKE_TIMESTAMPS.timeLeft,
|
|
4794
5125
|
expiryTime: FAKE_TIMESTAMPS.expiryTime,
|
|
@@ -4817,9 +5148,12 @@ describe('plugin-meetings', () => {
|
|
|
4817
5148
|
assert.calledWith(meeting.updateMeetingActions);
|
|
4818
5149
|
|
|
4819
5150
|
assert.calledWith(
|
|
4820
|
-
Metrics.sendBehavioralMetric,
|
|
5151
|
+
Metrics.sendBehavioralMetric,
|
|
5152
|
+
BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH_ERROR,
|
|
5153
|
+
{
|
|
4821
5154
|
correlationId: meeting.correlationId,
|
|
4822
|
-
reason:
|
|
5155
|
+
reason:
|
|
5156
|
+
'Not allowed to execute the function, some properties on server, or local client state do not allow you to complete this action.',
|
|
4823
5157
|
stack: sinon.match.any,
|
|
4824
5158
|
}
|
|
4825
5159
|
);
|
|
@@ -4838,13 +5172,18 @@ describe('plugin-meetings', () => {
|
|
|
4838
5172
|
assert.deepEqual(meeting.meetingInfo, {
|
|
4839
5173
|
...FAKE_MEETING_INFO,
|
|
4840
5174
|
});
|
|
4841
|
-
assert.equal(
|
|
5175
|
+
assert.equal(
|
|
5176
|
+
meeting.meetingInfoFailureReason,
|
|
5177
|
+
MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD
|
|
5178
|
+
);
|
|
4842
5179
|
assert.equal(meeting.requiredCaptcha, null);
|
|
4843
5180
|
assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
|
|
4844
5181
|
assert.calledWith(meeting.updateMeetingActions);
|
|
4845
5182
|
|
|
4846
5183
|
assert.calledWith(
|
|
4847
|
-
Metrics.sendBehavioralMetric,
|
|
5184
|
+
Metrics.sendBehavioralMetric,
|
|
5185
|
+
BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH_ERROR,
|
|
5186
|
+
{
|
|
4848
5187
|
correlationId: meeting.correlationId,
|
|
4849
5188
|
reason: 'Password is required, please use verifyPassword()',
|
|
4850
5189
|
stack: sinon.match.any,
|
|
@@ -4868,13 +5207,18 @@ describe('plugin-meetings', () => {
|
|
|
4868
5207
|
await assert.isRejected(meeting.refreshPermissionToken());
|
|
4869
5208
|
|
|
4870
5209
|
assert.calledOnce(meeting.attrs.meetingInfoProvider.fetchMeetingInfo);
|
|
4871
|
-
assert.equal(
|
|
5210
|
+
assert.equal(
|
|
5211
|
+
meeting.meetingInfoFailureReason,
|
|
5212
|
+
MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD
|
|
5213
|
+
);
|
|
4872
5214
|
assert.equal(meeting.requiredCaptcha, FAKE_SDK_CAPTCHA_INFO);
|
|
4873
5215
|
assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
|
|
4874
5216
|
assert.calledWith(meeting.updateMeetingActions);
|
|
4875
5217
|
|
|
4876
5218
|
assert.calledWith(
|
|
4877
|
-
Metrics.sendBehavioralMetric,
|
|
5219
|
+
Metrics.sendBehavioralMetric,
|
|
5220
|
+
BEHAVIORAL_METRICS.PERMISSION_TOKEN_REFRESH_ERROR,
|
|
5221
|
+
{
|
|
4878
5222
|
correlationId: meeting.correlationId,
|
|
4879
5223
|
reason: 'Captcha is required.',
|
|
4880
5224
|
stack: sinon.match.any,
|
|
@@ -5299,14 +5643,26 @@ describe('plugin-meetings', () => {
|
|
|
5299
5643
|
describe('#updateCallStateForMetrics', () => {
|
|
5300
5644
|
it('should update the callState, overriding existing values', () => {
|
|
5301
5645
|
assert.deepEqual(meeting.callStateForMetrics, {correlationId});
|
|
5302
|
-
meeting.updateCallStateForMetrics({
|
|
5303
|
-
|
|
5646
|
+
meeting.updateCallStateForMetrics({
|
|
5647
|
+
correlationId: uuid1,
|
|
5648
|
+
joinTrigger: 'jt',
|
|
5649
|
+
loginType: 'lt',
|
|
5650
|
+
});
|
|
5651
|
+
assert.deepEqual(meeting.callStateForMetrics, {
|
|
5652
|
+
correlationId: uuid1,
|
|
5653
|
+
joinTrigger: 'jt',
|
|
5654
|
+
loginType: 'lt',
|
|
5655
|
+
});
|
|
5304
5656
|
});
|
|
5305
5657
|
|
|
5306
5658
|
it('should update the callState, keeping non-supplied values', () => {
|
|
5307
5659
|
assert.deepEqual(meeting.callStateForMetrics, {correlationId});
|
|
5308
5660
|
meeting.updateCallStateForMetrics({joinTrigger: 'jt', loginType: 'lt'});
|
|
5309
|
-
assert.deepEqual(meeting.callStateForMetrics, {
|
|
5661
|
+
assert.deepEqual(meeting.callStateForMetrics, {
|
|
5662
|
+
correlationId,
|
|
5663
|
+
joinTrigger: 'jt',
|
|
5664
|
+
loginType: 'lt',
|
|
5665
|
+
});
|
|
5310
5666
|
});
|
|
5311
5667
|
});
|
|
5312
5668
|
|
|
@@ -5320,35 +5676,35 @@ describe('plugin-meetings', () => {
|
|
|
5320
5676
|
beforeEach(() => {
|
|
5321
5677
|
audioStream = {
|
|
5322
5678
|
getSettings: sinon.stub().returns({
|
|
5323
|
-
deviceId: 'some device id'
|
|
5679
|
+
deviceId: 'some device id',
|
|
5324
5680
|
}),
|
|
5325
5681
|
on: sinon.stub(),
|
|
5326
5682
|
off: sinon.stub(),
|
|
5327
|
-
}
|
|
5683
|
+
};
|
|
5328
5684
|
|
|
5329
5685
|
videoStream = {
|
|
5330
5686
|
getSettings: sinon.stub().returns({
|
|
5331
|
-
deviceId: 'some device id'
|
|
5687
|
+
deviceId: 'some device id',
|
|
5332
5688
|
}),
|
|
5333
5689
|
on: sinon.stub(),
|
|
5334
5690
|
off: sinon.stub(),
|
|
5335
|
-
}
|
|
5691
|
+
};
|
|
5336
5692
|
|
|
5337
5693
|
audioShareStream = {
|
|
5338
5694
|
on: sinon.stub(),
|
|
5339
5695
|
off: sinon.stub(),
|
|
5340
5696
|
getSettings: sinon.stub().returns({
|
|
5341
|
-
deviceId: 'some device id'
|
|
5697
|
+
deviceId: 'some device id',
|
|
5342
5698
|
}),
|
|
5343
|
-
}
|
|
5699
|
+
};
|
|
5344
5700
|
|
|
5345
5701
|
videoShareStream = {
|
|
5346
5702
|
on: sinon.stub(),
|
|
5347
5703
|
off: sinon.stub(),
|
|
5348
5704
|
getSettings: sinon.stub().returns({
|
|
5349
|
-
deviceId: 'some device id'
|
|
5705
|
+
deviceId: 'some device id',
|
|
5350
5706
|
}),
|
|
5351
|
-
}
|
|
5707
|
+
};
|
|
5352
5708
|
|
|
5353
5709
|
meeting.requestScreenShareFloor = sinon.stub().resolves({});
|
|
5354
5710
|
meeting.releaseScreenShareFloor = sinon.stub().resolves({});
|
|
@@ -5359,20 +5715,32 @@ describe('plugin-meetings', () => {
|
|
|
5359
5715
|
};
|
|
5360
5716
|
meeting.isMultistream = true;
|
|
5361
5717
|
meeting.mediaProperties.webrtcMediaConnection = {};
|
|
5362
|
-
meeting.audio = {
|
|
5363
|
-
meeting.video = {
|
|
5718
|
+
meeting.audio = {handleLocalStreamChange: sinon.stub()};
|
|
5719
|
+
meeting.video = {handleLocalStreamChange: sinon.stub()};
|
|
5364
5720
|
fakeMultistreamRoapMediaConnection = {
|
|
5365
5721
|
createSendSlot: () => {
|
|
5366
5722
|
return {
|
|
5367
5723
|
publishStream: sinon.stub(),
|
|
5368
5724
|
unpublishStream: sinon.stub(),
|
|
5369
|
-
}
|
|
5370
|
-
}
|
|
5371
|
-
}
|
|
5372
|
-
meeting.sendSlotManager.createSlot(
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5725
|
+
};
|
|
5726
|
+
},
|
|
5727
|
+
};
|
|
5728
|
+
meeting.sendSlotManager.createSlot(
|
|
5729
|
+
fakeMultistreamRoapMediaConnection,
|
|
5730
|
+
MediaType.VideoSlides
|
|
5731
|
+
);
|
|
5732
|
+
meeting.sendSlotManager.createSlot(
|
|
5733
|
+
fakeMultistreamRoapMediaConnection,
|
|
5734
|
+
MediaType.AudioSlides
|
|
5735
|
+
);
|
|
5736
|
+
meeting.sendSlotManager.createSlot(
|
|
5737
|
+
fakeMultistreamRoapMediaConnection,
|
|
5738
|
+
MediaType.AudioMain
|
|
5739
|
+
);
|
|
5740
|
+
meeting.sendSlotManager.createSlot(
|
|
5741
|
+
fakeMultistreamRoapMediaConnection,
|
|
5742
|
+
MediaType.VideoMain
|
|
5743
|
+
);
|
|
5376
5744
|
});
|
|
5377
5745
|
afterEach(() => {
|
|
5378
5746
|
sinon.restore();
|
|
@@ -5496,18 +5864,14 @@ describe('plugin-meetings', () => {
|
|
|
5496
5864
|
});
|
|
5497
5865
|
|
|
5498
5866
|
const checkAudioUnpublished = () => {
|
|
5499
|
-
assert.calledOnce(
|
|
5500
|
-
meeting.sendSlotManager.getSlot(MediaType.AudioMain).unpublishStream
|
|
5501
|
-
);
|
|
5867
|
+
assert.calledOnce(meeting.sendSlotManager.getSlot(MediaType.AudioMain).unpublishStream);
|
|
5502
5868
|
|
|
5503
5869
|
assert.equal(meeting.mediaProperties.audioStream, null);
|
|
5504
5870
|
assert.equal(meeting.mediaProperties.mediaDirection.sendAudio, 'fake value');
|
|
5505
5871
|
};
|
|
5506
5872
|
|
|
5507
5873
|
const checkVideoUnpublished = () => {
|
|
5508
|
-
assert.calledOnce(
|
|
5509
|
-
meeting.sendSlotManager.getSlot(MediaType.VideoMain).unpublishStream
|
|
5510
|
-
);
|
|
5874
|
+
assert.calledOnce(meeting.sendSlotManager.getSlot(MediaType.VideoMain).unpublishStream);
|
|
5511
5875
|
|
|
5512
5876
|
assert.equal(meeting.mediaProperties.videoStream, null);
|
|
5513
5877
|
assert.equal(meeting.mediaProperties.mediaDirection.sendVideo, 'fake value');
|
|
@@ -5540,12 +5904,22 @@ describe('plugin-meetings', () => {
|
|
|
5540
5904
|
it('fails if there is no media connection', async () => {
|
|
5541
5905
|
meeting.mediaProperties.webrtcMediaConnection = undefined;
|
|
5542
5906
|
await assert.isRejected(
|
|
5543
|
-
meeting.unpublishStreams([
|
|
5907
|
+
meeting.unpublishStreams([
|
|
5908
|
+
audioStream,
|
|
5909
|
+
videoStream,
|
|
5910
|
+
videoShareStream,
|
|
5911
|
+
audioShareStream,
|
|
5912
|
+
])
|
|
5544
5913
|
);
|
|
5545
5914
|
});
|
|
5546
5915
|
|
|
5547
5916
|
it('un-publishes the streams correctly (all 4 together)', async () => {
|
|
5548
|
-
await meeting.unpublishStreams([
|
|
5917
|
+
await meeting.unpublishStreams([
|
|
5918
|
+
audioStream,
|
|
5919
|
+
videoStream,
|
|
5920
|
+
videoShareStream,
|
|
5921
|
+
audioShareStream,
|
|
5922
|
+
]);
|
|
5549
5923
|
|
|
5550
5924
|
checkAudioUnpublished();
|
|
5551
5925
|
checkVideoUnpublished();
|
|
@@ -5605,40 +5979,48 @@ describe('plugin-meetings', () => {
|
|
|
5605
5979
|
return {
|
|
5606
5980
|
setCodecParameters: sinon.stub().resolves(),
|
|
5607
5981
|
deleteCodecParameters: sinon.stub().resolves(),
|
|
5608
|
-
}
|
|
5609
|
-
}
|
|
5982
|
+
};
|
|
5983
|
+
},
|
|
5610
5984
|
};
|
|
5611
|
-
meeting.sendSlotManager.createSlot(
|
|
5985
|
+
meeting.sendSlotManager.createSlot(
|
|
5986
|
+
fakeMultistreamRoapMediaConnection,
|
|
5987
|
+
MediaType.AudioMain,
|
|
5988
|
+
false
|
|
5989
|
+
);
|
|
5612
5990
|
meeting.mediaProperties.webrtcMediaConnection = {};
|
|
5613
5991
|
});
|
|
5614
5992
|
afterEach(() => {
|
|
5615
5993
|
sinon.restore();
|
|
5616
5994
|
});
|
|
5617
|
-
[
|
|
5618
|
-
{shouldEnableMusicMode
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
});
|
|
5995
|
+
[{shouldEnableMusicMode: true}, {shouldEnableMusicMode: false}].forEach(
|
|
5996
|
+
({shouldEnableMusicMode}) => {
|
|
5997
|
+
it(`fails if there is no media connection for shouldEnableMusicMode: ${shouldEnableMusicMode}`, async () => {
|
|
5998
|
+
meeting.mediaProperties.webrtcMediaConnection = undefined;
|
|
5999
|
+
await assert.isRejected(meeting.enableMusicMode(shouldEnableMusicMode));
|
|
6000
|
+
});
|
|
6001
|
+
}
|
|
6002
|
+
);
|
|
5626
6003
|
|
|
5627
6004
|
it('should set the codec parameters when shouldEnableMusicMode is true', async () => {
|
|
5628
6005
|
await meeting.enableMusicMode(true);
|
|
5629
|
-
assert.calledOnceWithExactly(
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
6006
|
+
assert.calledOnceWithExactly(
|
|
6007
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).setCodecParameters,
|
|
6008
|
+
{
|
|
6009
|
+
maxaveragebitrate: '64000',
|
|
6010
|
+
maxplaybackrate: '48000',
|
|
6011
|
+
}
|
|
6012
|
+
);
|
|
6013
|
+
assert.notCalled(
|
|
6014
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).deleteCodecParameters
|
|
6015
|
+
);
|
|
5634
6016
|
});
|
|
5635
6017
|
|
|
5636
6018
|
it('should set the codec parameters when shouldEnableMusicMode is false', async () => {
|
|
5637
6019
|
await meeting.enableMusicMode(false);
|
|
5638
|
-
assert.calledOnceWithExactly(
|
|
5639
|
-
|
|
5640
|
-
'maxplaybackrate'
|
|
5641
|
-
|
|
6020
|
+
assert.calledOnceWithExactly(
|
|
6021
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).deleteCodecParameters,
|
|
6022
|
+
['maxaveragebitrate', 'maxplaybackrate']
|
|
6023
|
+
);
|
|
5642
6024
|
assert.notCalled(meeting.sendSlotManager.getSlot(MediaType.AudioMain).setCodecParameters);
|
|
5643
6025
|
});
|
|
5644
6026
|
});
|
|
@@ -5649,8 +6031,8 @@ describe('plugin-meetings', () => {
|
|
|
5649
6031
|
beforeEach(() => {
|
|
5650
6032
|
const fakeMediaStream = () => {
|
|
5651
6033
|
return {
|
|
5652
|
-
id: 'fake stream'
|
|
5653
|
-
}
|
|
6034
|
+
id: 'fake stream',
|
|
6035
|
+
};
|
|
5654
6036
|
};
|
|
5655
6037
|
|
|
5656
6038
|
sandbox = sinon.createSandbox();
|
|
@@ -5717,7 +6099,7 @@ describe('plugin-meetings', () => {
|
|
|
5717
6099
|
} catch (err) {
|
|
5718
6100
|
assert.fail('reconnect should not error after clean up');
|
|
5719
6101
|
}
|
|
5720
|
-
})
|
|
6102
|
+
});
|
|
5721
6103
|
|
|
5722
6104
|
it('should trigger reconnection success and send CA metric', async () => {
|
|
5723
6105
|
await meeting.reconnect();
|
|
@@ -5737,7 +6119,10 @@ describe('plugin-meetings', () => {
|
|
|
5737
6119
|
meetingId: meeting.id,
|
|
5738
6120
|
},
|
|
5739
6121
|
});
|
|
5740
|
-
assert.calledOnceWithExactly(
|
|
6122
|
+
assert.calledOnceWithExactly(
|
|
6123
|
+
meeting.reconnectionManager.setStatus,
|
|
6124
|
+
RECONNECTION.STATE.COMPLETE
|
|
6125
|
+
);
|
|
5741
6126
|
});
|
|
5742
6127
|
|
|
5743
6128
|
it('should reset after reconnection success', async () => {
|
|
@@ -5832,7 +6217,7 @@ describe('plugin-meetings', () => {
|
|
|
5832
6217
|
let eventListeners;
|
|
5833
6218
|
const fakeStream = {
|
|
5834
6219
|
id: 'stream',
|
|
5835
|
-
getTracks: () => [{
|
|
6220
|
+
getTracks: () => [{id: 'track', addEventListener: sinon.stub()}],
|
|
5836
6221
|
};
|
|
5837
6222
|
|
|
5838
6223
|
beforeEach(() => {
|
|
@@ -5899,7 +6284,7 @@ describe('plugin-meetings', () => {
|
|
|
5899
6284
|
});
|
|
5900
6285
|
|
|
5901
6286
|
assert.notCalled(webex.internal.newMetrics.submitClientEvent);
|
|
5902
|
-
})
|
|
6287
|
+
});
|
|
5903
6288
|
|
|
5904
6289
|
it('sends client.ice.start correctly when hasMediaConnectionConnectedAtLeastOnce = false', () => {
|
|
5905
6290
|
meeting.hasMediaConnectionConnectedAtLeastOnce = false;
|
|
@@ -5915,7 +6300,7 @@ describe('plugin-meetings', () => {
|
|
|
5915
6300
|
meetingId: meeting.id,
|
|
5916
6301
|
},
|
|
5917
6302
|
});
|
|
5918
|
-
})
|
|
6303
|
+
});
|
|
5919
6304
|
});
|
|
5920
6305
|
|
|
5921
6306
|
describe('submitClientEvent on connectionSuccess', () => {
|
|
@@ -6043,22 +6428,17 @@ describe('plugin-meetings', () => {
|
|
|
6043
6428
|
|
|
6044
6429
|
const checkBehavioralMetricSent = (hasMediaConnectionConnectedAtLeastOnce = false) => {
|
|
6045
6430
|
assert.calledOnce(Metrics.sendBehavioralMetric);
|
|
6046
|
-
assert.calledWith(
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
networkStatus: meeting.networkStatus,
|
|
6053
|
-
hasMediaConnectionConnectedAtLeastOnce,
|
|
6054
|
-
},
|
|
6055
|
-
);
|
|
6431
|
+
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.CONNECTION_FAILURE, {
|
|
6432
|
+
correlation_id: meeting.correlationId,
|
|
6433
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
|
6434
|
+
networkStatus: meeting.networkStatus,
|
|
6435
|
+
hasMediaConnectionConnectedAtLeastOnce,
|
|
6436
|
+
});
|
|
6056
6437
|
};
|
|
6057
6438
|
|
|
6058
6439
|
it('handles "Disconnected" state correctly when waitForIceReconnect resolves', async () => {
|
|
6059
6440
|
meeting.reconnectionManager.waitForIceReconnect = sinon.stub().resolves();
|
|
6060
6441
|
|
|
6061
|
-
|
|
6062
6442
|
mockDisconnectedEvent();
|
|
6063
6443
|
|
|
6064
6444
|
await testUtils.flushPromises();
|
|
@@ -6072,14 +6452,13 @@ describe('plugin-meetings', () => {
|
|
|
6072
6452
|
|
|
6073
6453
|
it('handles "Disconnected" state correctly when waitForIceReconnect rejects and hasMediaConnectionConnectedAtLeastOnce = true', async () => {
|
|
6074
6454
|
const FAKE_ERROR = {fatal: true};
|
|
6075
|
-
const getErrorPayloadForClientErrorCodeStub =
|
|
6076
|
-
.
|
|
6077
|
-
|
|
6455
|
+
const getErrorPayloadForClientErrorCodeStub =
|
|
6456
|
+
(webex.internal.newMetrics.callDiagnosticMetrics.getErrorPayloadForClientErrorCode =
|
|
6457
|
+
sinon.stub().returns(FAKE_ERROR));
|
|
6078
6458
|
meeting.waitForMediaConnectionConnected = sinon.stub().resolves();
|
|
6079
6459
|
meeting.reconnectionManager.waitForIceReconnect = sinon.stub().rejects();
|
|
6080
6460
|
meeting.hasMediaConnectionConnectedAtLeastOnce = true;
|
|
6081
6461
|
|
|
6082
|
-
|
|
6083
6462
|
mockDisconnectedEvent();
|
|
6084
6463
|
|
|
6085
6464
|
await testUtils.flushPromises();
|
|
@@ -6094,7 +6473,6 @@ describe('plugin-meetings', () => {
|
|
|
6094
6473
|
it('handles "Disconnected" state correctly when waitForIceReconnect rejects and hasMediaConnectionConnectedAtLeastOnce = false', async () => {
|
|
6095
6474
|
meeting.reconnectionManager.waitForIceReconnect = sinon.stub().rejects();
|
|
6096
6475
|
|
|
6097
|
-
|
|
6098
6476
|
mockDisconnectedEvent();
|
|
6099
6477
|
|
|
6100
6478
|
await testUtils.flushPromises();
|
|
@@ -6108,7 +6486,6 @@ describe('plugin-meetings', () => {
|
|
|
6108
6486
|
});
|
|
6109
6487
|
|
|
6110
6488
|
describe('CONNECTION_STATE_CHANGED event when state = "Failed"', () => {
|
|
6111
|
-
|
|
6112
6489
|
const mockFailedEvent = () => {
|
|
6113
6490
|
meeting.setupMediaConnectionListeners();
|
|
6114
6491
|
eventListeners[Event.CONNECTION_STATE_CHANGED]({
|
|
@@ -6118,16 +6495,12 @@ describe('plugin-meetings', () => {
|
|
|
6118
6495
|
|
|
6119
6496
|
const checkBehavioralMetricSent = (hasMediaConnectionConnectedAtLeastOnce = false) => {
|
|
6120
6497
|
assert.calledOnce(Metrics.sendBehavioralMetric);
|
|
6121
|
-
assert.calledWith(
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
networkStatus: meeting.networkStatus,
|
|
6128
|
-
hasMediaConnectionConnectedAtLeastOnce,
|
|
6129
|
-
},
|
|
6130
|
-
);
|
|
6498
|
+
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.CONNECTION_FAILURE, {
|
|
6499
|
+
correlation_id: meeting.correlationId,
|
|
6500
|
+
locus_id: meeting.locusUrl.split('/').pop(),
|
|
6501
|
+
networkStatus: meeting.networkStatus,
|
|
6502
|
+
hasMediaConnectionConnectedAtLeastOnce,
|
|
6503
|
+
});
|
|
6131
6504
|
};
|
|
6132
6505
|
|
|
6133
6506
|
it('handles "Failed" state correctly when hasMediaConnectionConnectedAtLeastOnce = false', async () => {
|
|
@@ -6426,7 +6799,7 @@ describe('plugin-meetings', () => {
|
|
|
6426
6799
|
|
|
6427
6800
|
it('handles OFFER message correctly when request fails', async () => {
|
|
6428
6801
|
const clock = sinon.useFakeTimers();
|
|
6429
|
-
sinon.spy(clock,
|
|
6802
|
+
sinon.spy(clock, 'clearTimeout');
|
|
6430
6803
|
meeting.deferSDPAnswer = {reject: sinon.stub()};
|
|
6431
6804
|
meeting.sdpResponseTimer = '1234';
|
|
6432
6805
|
sendRoapMediaRequestStub.rejects();
|
|
@@ -7121,8 +7494,8 @@ describe('plugin-meetings', () => {
|
|
|
7121
7494
|
newLocusServices.services.webcast.url
|
|
7122
7495
|
);
|
|
7123
7496
|
assert.calledWith(
|
|
7124
|
-
|
|
7125
|
-
|
|
7497
|
+
meeting.webinar.webinarAttendeesSearchingUrlUpdate,
|
|
7498
|
+
newLocusServices.services.webinarAttendeesSearching.url
|
|
7126
7499
|
);
|
|
7127
7500
|
assert.calledOnce(meeting.recordingController.setSessionId);
|
|
7128
7501
|
done();
|
|
@@ -7298,20 +7671,19 @@ describe('plugin-meetings', () => {
|
|
|
7298
7671
|
});
|
|
7299
7672
|
|
|
7300
7673
|
describe('#setPermissionTokenPayload', () => {
|
|
7301
|
-
|
|
7302
7674
|
let now;
|
|
7303
7675
|
let clock;
|
|
7304
|
-
|
|
7676
|
+
|
|
7305
7677
|
beforeEach(() => {
|
|
7306
7678
|
now = Date.now();
|
|
7307
|
-
|
|
7679
|
+
|
|
7308
7680
|
// mock `new Date()` with constant `now`
|
|
7309
7681
|
clock = sinon.useFakeTimers(now);
|
|
7310
7682
|
});
|
|
7311
|
-
|
|
7683
|
+
|
|
7312
7684
|
afterEach(() => {
|
|
7313
7685
|
clock.restore();
|
|
7314
|
-
})
|
|
7686
|
+
});
|
|
7315
7687
|
it('sets correctly', () => {
|
|
7316
7688
|
assert.notOk(meeting.permissionTokenPayload);
|
|
7317
7689
|
|
|
@@ -7333,10 +7705,12 @@ describe('plugin-meetings', () => {
|
|
|
7333
7705
|
|
|
7334
7706
|
const testUrl = 'https://example.com';
|
|
7335
7707
|
|
|
7336
|
-
const policyData = {
|
|
7337
|
-
|
|
7338
|
-
|
|
7339
|
-
|
|
7708
|
+
const policyData = {
|
|
7709
|
+
permission: {
|
|
7710
|
+
userPolicies: {a: true},
|
|
7711
|
+
enforceVBGImagesURL: testUrl,
|
|
7712
|
+
},
|
|
7713
|
+
};
|
|
7340
7714
|
meeting.permissionTokenPayload = policyData;
|
|
7341
7715
|
|
|
7342
7716
|
meeting.setSelfUserPolicies();
|
|
@@ -7437,8 +7811,11 @@ describe('plugin-meetings', () => {
|
|
|
7437
7811
|
assert.equal(meeting.permissionToken, expectedInfoToParse.permissionToken);
|
|
7438
7812
|
assert.deepEqual(meeting.selfUserPolicies, expectedInfoToParse.selfUserPolicies);
|
|
7439
7813
|
|
|
7440
|
-
if(expectedInfoToParse.permissionTokenPayload) {
|
|
7441
|
-
assert.deepEqual(
|
|
7814
|
+
if (expectedInfoToParse.permissionTokenPayload) {
|
|
7815
|
+
assert.deepEqual(
|
|
7816
|
+
meeting.permissionTokenPayload,
|
|
7817
|
+
expectedInfoToParse.permissionTokenPayload
|
|
7818
|
+
);
|
|
7442
7819
|
}
|
|
7443
7820
|
};
|
|
7444
7821
|
|
|
@@ -7447,12 +7824,12 @@ describe('plugin-meetings', () => {
|
|
|
7447
7824
|
meeting.config.experimental.enableUnifiedMeetings = true;
|
|
7448
7825
|
|
|
7449
7826
|
const expectedPermissionTokenPayload = {
|
|
7450
|
-
exp:
|
|
7827
|
+
exp: '123456',
|
|
7451
7828
|
permission: {
|
|
7452
7829
|
userPolicies: {
|
|
7453
|
-
a: true
|
|
7454
|
-
}
|
|
7455
|
-
}
|
|
7830
|
+
a: true,
|
|
7831
|
+
},
|
|
7832
|
+
},
|
|
7456
7833
|
};
|
|
7457
7834
|
|
|
7458
7835
|
// generated permissionToken with secret `secret` and
|
|
@@ -7461,16 +7838,14 @@ describe('plugin-meetings', () => {
|
|
|
7461
7838
|
'eyJhbGciOiJIUzI1NiJ9.eyJleHAiOiIxMjM0NTYiLCJwZXJtaXNzaW9uIjp7InVzZXJQb2xpY2llcyI6eyJhIjp0cnVlfX19.wkTk0Hp8sUlq2wi2nP4-Ym4Xb7aEUHzyXA1kzk6f0V0';
|
|
7462
7839
|
|
|
7463
7840
|
const FAKE_MEETING_INFO = {
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
owner: test2,
|
|
7473
|
-
},
|
|
7841
|
+
conversationUrl: uuid1,
|
|
7842
|
+
locusUrl: url1,
|
|
7843
|
+
meetingJoinUrl: url2,
|
|
7844
|
+
meetingNumber: '12345',
|
|
7845
|
+
permissionToken,
|
|
7846
|
+
sipMeetingUri: test1,
|
|
7847
|
+
sipUrl: test1,
|
|
7848
|
+
owner: test2,
|
|
7474
7849
|
};
|
|
7475
7850
|
|
|
7476
7851
|
meeting.parseMeetingInfo(FAKE_MEETING_INFO);
|
|
@@ -7484,7 +7859,7 @@ describe('plugin-meetings', () => {
|
|
|
7484
7859
|
owner: test2,
|
|
7485
7860
|
selfUserPolicies: {a: true},
|
|
7486
7861
|
permissionToken,
|
|
7487
|
-
permissionTokenPayload: expectedPermissionTokenPayload
|
|
7862
|
+
permissionTokenPayload: expectedPermissionTokenPayload,
|
|
7488
7863
|
};
|
|
7489
7864
|
|
|
7490
7865
|
checkParseMeetingInfo(expectedInfoToParse);
|
|
@@ -7502,16 +7877,14 @@ describe('plugin-meetings', () => {
|
|
|
7502
7877
|
},
|
|
7503
7878
|
};
|
|
7504
7879
|
const FAKE_MEETING_INFO = {
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
owner: test2,
|
|
7514
|
-
},
|
|
7880
|
+
conversationUrl: uuid1,
|
|
7881
|
+
locusUrl: url1,
|
|
7882
|
+
meetingJoinUrl: url2,
|
|
7883
|
+
meetingNumber: '12345',
|
|
7884
|
+
permissionToken: 'abc',
|
|
7885
|
+
sipMeetingUri: test1,
|
|
7886
|
+
sipUrl: test1,
|
|
7887
|
+
owner: test2,
|
|
7515
7888
|
};
|
|
7516
7889
|
|
|
7517
7890
|
meeting.parseMeetingInfo(FAKE_MEETING_INFO, FAKE_LOCUS_MEETING);
|
|
@@ -7531,16 +7904,14 @@ describe('plugin-meetings', () => {
|
|
|
7531
7904
|
meeting.config.experimental = {enableMediaNegotiatedEvent: true};
|
|
7532
7905
|
meeting.config.experimental.enableUnifiedMeetings = true;
|
|
7533
7906
|
const FAKE_MEETING_INFO = {
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
owner: test2,
|
|
7543
|
-
},
|
|
7907
|
+
conversationUrl: uuid1,
|
|
7908
|
+
locusUrl: url1,
|
|
7909
|
+
meetingJoinUrl: url2,
|
|
7910
|
+
meetingNumber: '12345',
|
|
7911
|
+
permissionToken: 'abc',
|
|
7912
|
+
sipMeetingUri: test1,
|
|
7913
|
+
sipUrl: test1,
|
|
7914
|
+
owner: test2,
|
|
7544
7915
|
};
|
|
7545
7916
|
|
|
7546
7917
|
meeting.parseMeetingInfo(FAKE_MEETING_INFO);
|
|
@@ -7561,16 +7932,14 @@ describe('plugin-meetings', () => {
|
|
|
7561
7932
|
meeting.config.experimental.enableUnifiedMeetings = true;
|
|
7562
7933
|
const FAKE_STRING_DESTINATION = 'sipUrl';
|
|
7563
7934
|
const FAKE_MEETING_INFO = {
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
owner: test2,
|
|
7573
|
-
},
|
|
7935
|
+
conversationUrl: uuid1,
|
|
7936
|
+
locusUrl: url1,
|
|
7937
|
+
meetingJoinUrl: url2,
|
|
7938
|
+
meetingNumber: '12345',
|
|
7939
|
+
permissionToken: 'abc',
|
|
7940
|
+
sipMeetingUri: test1,
|
|
7941
|
+
sipUrl: test1,
|
|
7942
|
+
owner: test2,
|
|
7574
7943
|
};
|
|
7575
7944
|
|
|
7576
7945
|
meeting.parseMeetingInfo(FAKE_MEETING_INFO, FAKE_STRING_DESTINATION);
|
|
@@ -7589,24 +7958,42 @@ describe('plugin-meetings', () => {
|
|
|
7589
7958
|
it('should parse interpretation info correctly', () => {
|
|
7590
7959
|
const parseInterpretationInfo = sinon.spy(MeetingUtil, 'parseInterpretationInfo');
|
|
7591
7960
|
const mockToggleOnData = {
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
],
|
|
7605
|
-
},
|
|
7961
|
+
meetingSiteSetting: {
|
|
7962
|
+
enableHostInterpreterControlSI: true,
|
|
7963
|
+
},
|
|
7964
|
+
turnOnSimultaneousInterpretation: true,
|
|
7965
|
+
simultaneousInterpretation: {
|
|
7966
|
+
currentSIInterpreter: false,
|
|
7967
|
+
siLanguages: [
|
|
7968
|
+
{
|
|
7969
|
+
languageCode: 'ar',
|
|
7970
|
+
languageGroupId: 4,
|
|
7971
|
+
},
|
|
7972
|
+
],
|
|
7606
7973
|
},
|
|
7607
7974
|
};
|
|
7608
7975
|
meeting.parseMeetingInfo(mockToggleOnData);
|
|
7609
|
-
assert.calledOnceWithExactly(parseInterpretationInfo, meeting, mockToggleOnData
|
|
7976
|
+
assert.calledOnceWithExactly(parseInterpretationInfo, meeting, mockToggleOnData);
|
|
7977
|
+
});
|
|
7978
|
+
|
|
7979
|
+
it('should handle error', () => {
|
|
7980
|
+
const parseInterpretationInfo = sinon.spy(MeetingUtil, 'parseInterpretationInfo');
|
|
7981
|
+
const FAKE_MEETING_INFO = {
|
|
7982
|
+
conversationUrl: uuid1,
|
|
7983
|
+
locusUrl: url1,
|
|
7984
|
+
meetingJoinUrl: url2,
|
|
7985
|
+
meetingNumber: '12345',
|
|
7986
|
+
permissionToken: 'abc',
|
|
7987
|
+
sipMeetingUri: test1,
|
|
7988
|
+
sipUrl: test1,
|
|
7989
|
+
owner: test2,
|
|
7990
|
+
};
|
|
7991
|
+
meeting.parseMeetingInfo(FAKE_MEETING_INFO, undefined, 'Error');
|
|
7992
|
+
|
|
7993
|
+
checkParseMeetingInfo({
|
|
7994
|
+
locusUrl: meeting.locusUrl,
|
|
7995
|
+
});
|
|
7996
|
+
assert.calledOnceWithExactly(parseInterpretationInfo, meeting, FAKE_MEETING_INFO);
|
|
7610
7997
|
});
|
|
7611
7998
|
});
|
|
7612
7999
|
|
|
@@ -8723,7 +9110,6 @@ describe('plugin-meetings', () => {
|
|
|
8723
9110
|
REMOTE_B: 'remote-user-B-url',
|
|
8724
9111
|
};
|
|
8725
9112
|
|
|
8726
|
-
|
|
8727
9113
|
const generateContent = (
|
|
8728
9114
|
beneficiaryId = null,
|
|
8729
9115
|
disposition = null,
|
|
@@ -8732,7 +9118,7 @@ describe('plugin-meetings', () => {
|
|
|
8732
9118
|
) => ({
|
|
8733
9119
|
beneficiaryId,
|
|
8734
9120
|
disposition,
|
|
8735
|
-
deviceUrlSharing
|
|
9121
|
+
deviceUrlSharing,
|
|
8736
9122
|
});
|
|
8737
9123
|
const generateWhiteboard = (
|
|
8738
9124
|
beneficiaryId = null,
|
|
@@ -8751,7 +9137,7 @@ describe('plugin-meetings', () => {
|
|
|
8751
9137
|
annotation,
|
|
8752
9138
|
url,
|
|
8753
9139
|
shareInstanceId,
|
|
8754
|
-
deviceUrlSharing
|
|
9140
|
+
deviceUrlSharing
|
|
8755
9141
|
) => {
|
|
8756
9142
|
const newPayload = cloneDeep(payload);
|
|
8757
9143
|
|
|
@@ -9196,7 +9582,7 @@ describe('plugin-meetings', () => {
|
|
|
9196
9582
|
true,
|
|
9197
9583
|
false,
|
|
9198
9584
|
USER_IDS.ME,
|
|
9199
|
-
RESOURCE_URLS.WHITEBOARD_A
|
|
9585
|
+
RESOURCE_URLS.WHITEBOARD_A
|
|
9200
9586
|
);
|
|
9201
9587
|
const data2 = generateData(
|
|
9202
9588
|
data1.payload,
|
|
@@ -9205,7 +9591,7 @@ describe('plugin-meetings', () => {
|
|
|
9205
9591
|
USER_IDS.ME,
|
|
9206
9592
|
RESOURCE_URLS.WHITEBOARD_A,
|
|
9207
9593
|
true,
|
|
9208
|
-
USER_IDS.ME
|
|
9594
|
+
USER_IDS.ME
|
|
9209
9595
|
);
|
|
9210
9596
|
const data3 = generateData(
|
|
9211
9597
|
data2.payload,
|
|
@@ -9218,9 +9604,21 @@ describe('plugin-meetings', () => {
|
|
|
9218
9604
|
undefined,
|
|
9219
9605
|
undefined,
|
|
9220
9606
|
undefined,
|
|
9221
|
-
DEVICE_URL.LOCAL_WEB
|
|
9607
|
+
DEVICE_URL.LOCAL_WEB
|
|
9608
|
+
);
|
|
9609
|
+
const data4 = generateData(
|
|
9610
|
+
data3.payload,
|
|
9611
|
+
false,
|
|
9612
|
+
true,
|
|
9613
|
+
USER_IDS.ME,
|
|
9614
|
+
undefined,
|
|
9615
|
+
undefined,
|
|
9616
|
+
undefined,
|
|
9617
|
+
undefined,
|
|
9618
|
+
undefined,
|
|
9619
|
+
undefined,
|
|
9620
|
+
DEVICE_URL.LOCAL_WEB
|
|
9222
9621
|
);
|
|
9223
|
-
const data4 = generateData(data3.payload, false, true, USER_IDS.ME, undefined, undefined, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
|
|
9224
9622
|
|
|
9225
9623
|
payloadTestHelper([data1, data2, data3, data4]);
|
|
9226
9624
|
});
|
|
@@ -9253,7 +9651,7 @@ describe('plugin-meetings', () => {
|
|
|
9253
9651
|
undefined,
|
|
9254
9652
|
undefined,
|
|
9255
9653
|
undefined,
|
|
9256
|
-
DEVICE_URL.REMOTE_A
|
|
9654
|
+
DEVICE_URL.REMOTE_A
|
|
9257
9655
|
);
|
|
9258
9656
|
const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_A);
|
|
9259
9657
|
|
|
@@ -9288,9 +9686,21 @@ describe('plugin-meetings', () => {
|
|
|
9288
9686
|
undefined,
|
|
9289
9687
|
undefined,
|
|
9290
9688
|
undefined,
|
|
9291
|
-
DEVICE_URL.LOCAL_WEB
|
|
9689
|
+
DEVICE_URL.LOCAL_WEB
|
|
9690
|
+
);
|
|
9691
|
+
const data4 = generateData(
|
|
9692
|
+
data3.payload,
|
|
9693
|
+
false,
|
|
9694
|
+
true,
|
|
9695
|
+
USER_IDS.ME,
|
|
9696
|
+
undefined,
|
|
9697
|
+
undefined,
|
|
9698
|
+
undefined,
|
|
9699
|
+
undefined,
|
|
9700
|
+
undefined,
|
|
9701
|
+
undefined,
|
|
9702
|
+
DEVICE_URL.LOCAL_WEB
|
|
9292
9703
|
);
|
|
9293
|
-
const data4 = generateData(data3.payload, false, true, USER_IDS.ME, undefined, undefined, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
|
|
9294
9704
|
|
|
9295
9705
|
payloadTestHelper([data1, data2, data3, data4]);
|
|
9296
9706
|
});
|
|
@@ -9323,7 +9733,7 @@ describe('plugin-meetings', () => {
|
|
|
9323
9733
|
undefined,
|
|
9324
9734
|
undefined,
|
|
9325
9735
|
undefined,
|
|
9326
|
-
DEVICE_URL.REMOTE_A
|
|
9736
|
+
DEVICE_URL.REMOTE_A
|
|
9327
9737
|
);
|
|
9328
9738
|
const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_A);
|
|
9329
9739
|
|
|
@@ -9358,7 +9768,7 @@ describe('plugin-meetings', () => {
|
|
|
9358
9768
|
undefined,
|
|
9359
9769
|
undefined,
|
|
9360
9770
|
undefined,
|
|
9361
|
-
DEVICE_URL.REMOTE_B
|
|
9771
|
+
DEVICE_URL.REMOTE_B
|
|
9362
9772
|
);
|
|
9363
9773
|
const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_B);
|
|
9364
9774
|
|
|
@@ -9368,7 +9778,19 @@ describe('plugin-meetings', () => {
|
|
|
9368
9778
|
|
|
9369
9779
|
describe('Desktop --> Whiteboard A', () => {
|
|
9370
9780
|
it('Scenario #1: you share desktop and then share whiteboard', () => {
|
|
9371
|
-
const data1 = generateData(
|
|
9781
|
+
const data1 = generateData(
|
|
9782
|
+
blankPayload,
|
|
9783
|
+
true,
|
|
9784
|
+
true,
|
|
9785
|
+
USER_IDS.ME,
|
|
9786
|
+
undefined,
|
|
9787
|
+
false,
|
|
9788
|
+
undefined,
|
|
9789
|
+
undefined,
|
|
9790
|
+
undefined,
|
|
9791
|
+
undefined,
|
|
9792
|
+
DEVICE_URL.LOCAL_WEB
|
|
9793
|
+
);
|
|
9372
9794
|
const data2 = generateData(
|
|
9373
9795
|
data1.payload,
|
|
9374
9796
|
true,
|
|
@@ -9382,7 +9804,19 @@ describe('plugin-meetings', () => {
|
|
|
9382
9804
|
});
|
|
9383
9805
|
|
|
9384
9806
|
it('Scenario #2: you share desktop and remote person A shares whiteboard', () => {
|
|
9385
|
-
const data1 = generateData(
|
|
9807
|
+
const data1 = generateData(
|
|
9808
|
+
blankPayload,
|
|
9809
|
+
true,
|
|
9810
|
+
true,
|
|
9811
|
+
USER_IDS.ME,
|
|
9812
|
+
undefined,
|
|
9813
|
+
false,
|
|
9814
|
+
undefined,
|
|
9815
|
+
undefined,
|
|
9816
|
+
undefined,
|
|
9817
|
+
undefined,
|
|
9818
|
+
DEVICE_URL.LOCAL_WEB
|
|
9819
|
+
);
|
|
9386
9820
|
const data2 = generateData(
|
|
9387
9821
|
data1.payload,
|
|
9388
9822
|
true,
|
|
@@ -9396,7 +9830,19 @@ describe('plugin-meetings', () => {
|
|
|
9396
9830
|
});
|
|
9397
9831
|
|
|
9398
9832
|
it('Scenario #3: remote person A shares desktop and you share whiteboard', () => {
|
|
9399
|
-
const data1 = generateData(
|
|
9833
|
+
const data1 = generateData(
|
|
9834
|
+
blankPayload,
|
|
9835
|
+
true,
|
|
9836
|
+
true,
|
|
9837
|
+
USER_IDS.REMOTE_A,
|
|
9838
|
+
undefined,
|
|
9839
|
+
false,
|
|
9840
|
+
undefined,
|
|
9841
|
+
undefined,
|
|
9842
|
+
undefined,
|
|
9843
|
+
undefined,
|
|
9844
|
+
DEVICE_URL.REMOTE_A
|
|
9845
|
+
);
|
|
9400
9846
|
const data2 = generateData(
|
|
9401
9847
|
data1.payload,
|
|
9402
9848
|
true,
|
|
@@ -9410,7 +9856,19 @@ describe('plugin-meetings', () => {
|
|
|
9410
9856
|
});
|
|
9411
9857
|
|
|
9412
9858
|
it('Scenario #4: remote person A shares desktop and then shares whiteboard', () => {
|
|
9413
|
-
const data1 = generateData(
|
|
9859
|
+
const data1 = generateData(
|
|
9860
|
+
blankPayload,
|
|
9861
|
+
true,
|
|
9862
|
+
true,
|
|
9863
|
+
USER_IDS.REMOTE_A,
|
|
9864
|
+
undefined,
|
|
9865
|
+
false,
|
|
9866
|
+
undefined,
|
|
9867
|
+
undefined,
|
|
9868
|
+
undefined,
|
|
9869
|
+
undefined,
|
|
9870
|
+
DEVICE_URL.REMOTE_A
|
|
9871
|
+
);
|
|
9414
9872
|
const data2 = generateData(
|
|
9415
9873
|
data1.payload,
|
|
9416
9874
|
true,
|
|
@@ -9424,7 +9882,19 @@ describe('plugin-meetings', () => {
|
|
|
9424
9882
|
});
|
|
9425
9883
|
|
|
9426
9884
|
it('Scenario #5: remote person A shares desktop and remote person B shares whiteboard', () => {
|
|
9427
|
-
const data1 = generateData(
|
|
9885
|
+
const data1 = generateData(
|
|
9886
|
+
blankPayload,
|
|
9887
|
+
true,
|
|
9888
|
+
true,
|
|
9889
|
+
USER_IDS.REMOTE_A,
|
|
9890
|
+
undefined,
|
|
9891
|
+
false,
|
|
9892
|
+
undefined,
|
|
9893
|
+
undefined,
|
|
9894
|
+
undefined,
|
|
9895
|
+
undefined,
|
|
9896
|
+
DEVICE_URL.REMOTE_A
|
|
9897
|
+
);
|
|
9428
9898
|
const data2 = generateData(
|
|
9429
9899
|
data1.payload,
|
|
9430
9900
|
true,
|
|
@@ -9439,26 +9909,146 @@ describe('plugin-meetings', () => {
|
|
|
9439
9909
|
});
|
|
9440
9910
|
describe('Desktop A --> Desktop B', () => {
|
|
9441
9911
|
it('Scenario #1: you share desktop using web client and then share using native client', () => {
|
|
9442
|
-
const data1 = generateData(
|
|
9443
|
-
|
|
9444
|
-
|
|
9445
|
-
|
|
9912
|
+
const data1 = generateData(
|
|
9913
|
+
blankPayload,
|
|
9914
|
+
true,
|
|
9915
|
+
true,
|
|
9916
|
+
USER_IDS.ME,
|
|
9917
|
+
undefined,
|
|
9918
|
+
false,
|
|
9919
|
+
undefined,
|
|
9920
|
+
undefined,
|
|
9921
|
+
undefined,
|
|
9922
|
+
undefined,
|
|
9923
|
+
DEVICE_URL.LOCAL_WEB
|
|
9924
|
+
);
|
|
9925
|
+
const data2 = generateData(
|
|
9926
|
+
data1.payload,
|
|
9927
|
+
false,
|
|
9928
|
+
true,
|
|
9929
|
+
USER_IDS.ME,
|
|
9930
|
+
undefined,
|
|
9931
|
+
false,
|
|
9932
|
+
undefined,
|
|
9933
|
+
undefined,
|
|
9934
|
+
undefined,
|
|
9935
|
+
undefined,
|
|
9936
|
+
DEVICE_URL.LOCAL_WEB
|
|
9937
|
+
);
|
|
9938
|
+
const data3 = generateData(
|
|
9939
|
+
data2.payload,
|
|
9940
|
+
true,
|
|
9941
|
+
true,
|
|
9942
|
+
USER_IDS.ME,
|
|
9943
|
+
undefined,
|
|
9944
|
+
false,
|
|
9945
|
+
undefined,
|
|
9946
|
+
undefined,
|
|
9947
|
+
undefined,
|
|
9948
|
+
undefined,
|
|
9949
|
+
DEVICE_URL.LOCAL_MAC
|
|
9950
|
+
);
|
|
9951
|
+
const data4 = generateData(
|
|
9952
|
+
data3.payload,
|
|
9953
|
+
false,
|
|
9954
|
+
true,
|
|
9955
|
+
USER_IDS.ME,
|
|
9956
|
+
undefined,
|
|
9957
|
+
false,
|
|
9958
|
+
undefined,
|
|
9959
|
+
undefined,
|
|
9960
|
+
undefined,
|
|
9961
|
+
undefined,
|
|
9962
|
+
DEVICE_URL.LOCAL_MAC
|
|
9963
|
+
);
|
|
9446
9964
|
|
|
9447
9965
|
payloadTestHelper([data1, data2, data3, data4]);
|
|
9448
9966
|
});
|
|
9449
9967
|
|
|
9450
9968
|
it('Scenario #2: you share desktop using web client and remote person A shares desktop', () => {
|
|
9451
|
-
const data1 = generateData(
|
|
9452
|
-
|
|
9453
|
-
|
|
9969
|
+
const data1 = generateData(
|
|
9970
|
+
blankPayload,
|
|
9971
|
+
true,
|
|
9972
|
+
true,
|
|
9973
|
+
USER_IDS.ME,
|
|
9974
|
+
undefined,
|
|
9975
|
+
false,
|
|
9976
|
+
undefined,
|
|
9977
|
+
undefined,
|
|
9978
|
+
undefined,
|
|
9979
|
+
undefined,
|
|
9980
|
+
DEVICE_URL.LOCAL_WEB
|
|
9981
|
+
);
|
|
9982
|
+
const data2 = generateData(
|
|
9983
|
+
data1.payload,
|
|
9984
|
+
true,
|
|
9985
|
+
true,
|
|
9986
|
+
USER_IDS.REMOTE_A,
|
|
9987
|
+
undefined,
|
|
9988
|
+
false,
|
|
9989
|
+
undefined,
|
|
9990
|
+
undefined,
|
|
9991
|
+
undefined,
|
|
9992
|
+
undefined,
|
|
9993
|
+
DEVICE_URL.REMOTE_A
|
|
9994
|
+
);
|
|
9995
|
+
const data3 = generateData(
|
|
9996
|
+
data2.payload,
|
|
9997
|
+
false,
|
|
9998
|
+
true,
|
|
9999
|
+
USER_IDS.REMOTE_A,
|
|
10000
|
+
undefined,
|
|
10001
|
+
false,
|
|
10002
|
+
undefined,
|
|
10003
|
+
undefined,
|
|
10004
|
+
undefined,
|
|
10005
|
+
undefined,
|
|
10006
|
+
DEVICE_URL.REMOTE_A
|
|
10007
|
+
);
|
|
9454
10008
|
|
|
9455
10009
|
payloadTestHelper([data1, data2, data3]);
|
|
9456
10010
|
});
|
|
9457
10011
|
|
|
9458
10012
|
it('Scenario #3: remote person A shares desktop and then you share desktop using web client', () => {
|
|
9459
|
-
const data1 = generateData(
|
|
9460
|
-
|
|
9461
|
-
|
|
10013
|
+
const data1 = generateData(
|
|
10014
|
+
blankPayload,
|
|
10015
|
+
true,
|
|
10016
|
+
true,
|
|
10017
|
+
USER_IDS.REMOTE_A,
|
|
10018
|
+
undefined,
|
|
10019
|
+
false,
|
|
10020
|
+
undefined,
|
|
10021
|
+
undefined,
|
|
10022
|
+
undefined,
|
|
10023
|
+
undefined,
|
|
10024
|
+
DEVICE_URL.REMOTE_A
|
|
10025
|
+
);
|
|
10026
|
+
const data2 = generateData(
|
|
10027
|
+
data1.payload,
|
|
10028
|
+
true,
|
|
10029
|
+
true,
|
|
10030
|
+
USER_IDS.ME,
|
|
10031
|
+
undefined,
|
|
10032
|
+
false,
|
|
10033
|
+
undefined,
|
|
10034
|
+
undefined,
|
|
10035
|
+
undefined,
|
|
10036
|
+
undefined,
|
|
10037
|
+
DEVICE_URL.LOCAL_WEB
|
|
10038
|
+
);
|
|
10039
|
+
const data3 = generateData(
|
|
10040
|
+
data2.payload,
|
|
10041
|
+
false,
|
|
10042
|
+
true,
|
|
10043
|
+
USER_IDS.ME,
|
|
10044
|
+
undefined,
|
|
10045
|
+
false,
|
|
10046
|
+
undefined,
|
|
10047
|
+
undefined,
|
|
10048
|
+
undefined,
|
|
10049
|
+
undefined,
|
|
10050
|
+
DEVICE_URL.LOCAL_WEB
|
|
10051
|
+
);
|
|
9462
10052
|
|
|
9463
10053
|
payloadTestHelper([data1, data2, data3]);
|
|
9464
10054
|
});
|
|
@@ -9472,8 +10062,32 @@ describe('plugin-meetings', () => {
|
|
|
9472
10062
|
});
|
|
9473
10063
|
|
|
9474
10064
|
it('Scenario #5: remote person A shares desktop A and remote person B shares desktop B', () => {
|
|
9475
|
-
const data1 = generateData(
|
|
9476
|
-
|
|
10065
|
+
const data1 = generateData(
|
|
10066
|
+
blankPayload,
|
|
10067
|
+
true,
|
|
10068
|
+
true,
|
|
10069
|
+
USER_IDS.REMOTE_A,
|
|
10070
|
+
undefined,
|
|
10071
|
+
false,
|
|
10072
|
+
undefined,
|
|
10073
|
+
undefined,
|
|
10074
|
+
undefined,
|
|
10075
|
+
undefined,
|
|
10076
|
+
DEVICE_URL.REMOTE_A
|
|
10077
|
+
);
|
|
10078
|
+
const data2 = generateData(
|
|
10079
|
+
data1.payload,
|
|
10080
|
+
true,
|
|
10081
|
+
true,
|
|
10082
|
+
USER_IDS.REMOTE_B,
|
|
10083
|
+
undefined,
|
|
10084
|
+
false,
|
|
10085
|
+
undefined,
|
|
10086
|
+
undefined,
|
|
10087
|
+
undefined,
|
|
10088
|
+
undefined,
|
|
10089
|
+
DEVICE_URL.REMOTE_B
|
|
10090
|
+
);
|
|
9477
10091
|
const data3 = generateData(data2.payload, false, true, USER_IDS.REMOTE_B);
|
|
9478
10092
|
|
|
9479
10093
|
payloadTestHelper([data1, data2, data3]);
|
|
@@ -9892,26 +10506,34 @@ describe('plugin-meetings', () => {
|
|
|
9892
10506
|
|
|
9893
10507
|
afterEach(() => {
|
|
9894
10508
|
clock.restore();
|
|
9895
|
-
})
|
|
10509
|
+
});
|
|
9896
10510
|
|
|
9897
10511
|
it('should return undefined if exp is undefined', () => {
|
|
9898
|
-
assert.equal(meeting.getPermissionTokenExpiryInfo(), undefined)
|
|
10512
|
+
assert.equal(meeting.getPermissionTokenExpiryInfo(), undefined);
|
|
9899
10513
|
});
|
|
9900
10514
|
|
|
9901
10515
|
it('should return the expected positive exp', () => {
|
|
9902
10516
|
// set permission token as now + 1 sec
|
|
9903
10517
|
const expiryTime = now + 1000;
|
|
9904
|
-
meeting.permissionTokenPayload = {exp:
|
|
10518
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: now};
|
|
9905
10519
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
9906
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10520
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10521
|
+
timeLeft: 1,
|
|
10522
|
+
expiryTime: Number(expiryTime),
|
|
10523
|
+
currentTime: now,
|
|
10524
|
+
});
|
|
9907
10525
|
});
|
|
9908
10526
|
|
|
9909
10527
|
it('should return the expected negative exp', () => {
|
|
9910
10528
|
// set permission token as now - 1 sec
|
|
9911
10529
|
const expiryTime = now - 1000;
|
|
9912
|
-
meeting.permissionTokenPayload = {exp:
|
|
10530
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: now};
|
|
9913
10531
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
9914
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10532
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10533
|
+
timeLeft: -1,
|
|
10534
|
+
expiryTime: Number(expiryTime),
|
|
10535
|
+
currentTime: now,
|
|
10536
|
+
});
|
|
9915
10537
|
});
|
|
9916
10538
|
|
|
9917
10539
|
describe('#getPermissionTokenExpiryInfo with wrong current time which is in future', () => {
|
|
@@ -9920,34 +10542,41 @@ describe('plugin-meetings', () => {
|
|
|
9920
10542
|
beforeEach(() => {
|
|
9921
10543
|
// current time is 3 hours off
|
|
9922
10544
|
now = Date.now() + 10800000;
|
|
9923
|
-
|
|
10545
|
+
|
|
9924
10546
|
// mock `new Date()` with constant `now`
|
|
9925
10547
|
clock = sinon.useFakeTimers(now);
|
|
9926
10548
|
});
|
|
9927
|
-
|
|
10549
|
+
|
|
9928
10550
|
afterEach(() => {
|
|
9929
10551
|
clock.restore();
|
|
9930
|
-
})
|
|
9931
|
-
|
|
10552
|
+
});
|
|
10553
|
+
|
|
9932
10554
|
it('should return the expected positive exp when client time is wrong', () => {
|
|
9933
10555
|
const serverTime = Date.now();
|
|
9934
|
-
|
|
9935
|
-
|
|
10556
|
+
|
|
10557
|
+
// set permission token as now + 1 sec
|
|
9936
10558
|
const expiryTime = serverTime + 1000;
|
|
9937
|
-
meeting.permissionTokenPayload = {exp:
|
|
10559
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: serverTime};
|
|
9938
10560
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
9939
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10561
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10562
|
+
timeLeft: 1,
|
|
10563
|
+
expiryTime: Number(expiryTime),
|
|
10564
|
+
currentTime: now,
|
|
10565
|
+
});
|
|
9940
10566
|
});
|
|
9941
|
-
|
|
10567
|
+
|
|
9942
10568
|
it('should return the expected negative exp when client time is wrong', () => {
|
|
9943
10569
|
const serverTime = Date.now();
|
|
9944
10570
|
// set permission token as now - 1 sec
|
|
9945
10571
|
const expiryTime = serverTime - 1000;
|
|
9946
|
-
meeting.permissionTokenPayload = {exp:
|
|
10572
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: serverTime};
|
|
9947
10573
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
9948
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10574
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10575
|
+
timeLeft: -1,
|
|
10576
|
+
expiryTime: Number(expiryTime),
|
|
10577
|
+
currentTime: now,
|
|
10578
|
+
});
|
|
9949
10579
|
});
|
|
9950
|
-
|
|
9951
10580
|
});
|
|
9952
10581
|
|
|
9953
10582
|
describe('#getPermissionTokenExpiryInfo with wrong current Time which is in the past', () => {
|
|
@@ -9956,42 +10585,47 @@ describe('plugin-meetings', () => {
|
|
|
9956
10585
|
beforeEach(() => {
|
|
9957
10586
|
// current time is 3 hours off
|
|
9958
10587
|
now = Date.now() - 10800000;
|
|
9959
|
-
|
|
10588
|
+
|
|
9960
10589
|
// mock `new Date()` with constant `now`
|
|
9961
10590
|
clock = sinon.useFakeTimers(now);
|
|
9962
10591
|
});
|
|
9963
|
-
|
|
10592
|
+
|
|
9964
10593
|
afterEach(() => {
|
|
9965
10594
|
clock.restore();
|
|
9966
|
-
})
|
|
9967
|
-
|
|
10595
|
+
});
|
|
10596
|
+
|
|
9968
10597
|
it('should return the expected positive exp when client time is wrong', () => {
|
|
9969
10598
|
const serverTime = Date.now();
|
|
9970
|
-
|
|
9971
|
-
|
|
10599
|
+
|
|
10600
|
+
// set permission token as now + 1 sec
|
|
9972
10601
|
const expiryTime = serverTime + 1000;
|
|
9973
|
-
meeting.permissionTokenPayload = {exp:
|
|
10602
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: serverTime};
|
|
9974
10603
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
9975
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10604
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10605
|
+
timeLeft: 1,
|
|
10606
|
+
expiryTime: Number(expiryTime),
|
|
10607
|
+
currentTime: now,
|
|
10608
|
+
});
|
|
9976
10609
|
});
|
|
9977
|
-
|
|
10610
|
+
|
|
9978
10611
|
it('should return the expected negative exp when client time is wrong', () => {
|
|
9979
10612
|
const serverTime = Date.now();
|
|
9980
10613
|
// set permission token as now - 1 sec
|
|
9981
10614
|
const expiryTime = serverTime - 1000;
|
|
9982
|
-
meeting.permissionTokenPayload = {exp:
|
|
10615
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: serverTime};
|
|
9983
10616
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
9984
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10617
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10618
|
+
timeLeft: -1,
|
|
10619
|
+
expiryTime: Number(expiryTime),
|
|
10620
|
+
currentTime: now,
|
|
10621
|
+
});
|
|
9985
10622
|
});
|
|
9986
|
-
|
|
9987
10623
|
});
|
|
9988
10624
|
});
|
|
9989
10625
|
|
|
9990
|
-
|
|
9991
|
-
|
|
9992
10626
|
describe('#checkAndRefreshPermissionToken', () => {
|
|
9993
|
-
it('should not fire refreshPermissionToken if permissionToken is not defined', async() => {
|
|
9994
|
-
meeting.getPermissionTokenExpiryInfo = sinon.stub().returns(undefined)
|
|
10627
|
+
it('should not fire refreshPermissionToken if permissionToken is not defined', async () => {
|
|
10628
|
+
meeting.getPermissionTokenExpiryInfo = sinon.stub().returns(undefined);
|
|
9995
10629
|
meeting.refreshPermissionToken = sinon.stub().returns(Promise.resolve('test return value'));
|
|
9996
10630
|
|
|
9997
10631
|
const returnValue = await meeting.checkAndRefreshPermissionToken(10, 'ttl-join');
|
|
@@ -10001,8 +10635,10 @@ describe('plugin-meetings', () => {
|
|
|
10001
10635
|
assert.equal(returnValue, undefined);
|
|
10002
10636
|
});
|
|
10003
10637
|
|
|
10004
|
-
it('should fire refreshPermissionToken if time left is below 10sec', async() => {
|
|
10005
|
-
meeting.getPermissionTokenExpiryInfo = sinon
|
|
10638
|
+
it('should fire refreshPermissionToken if time left is below 10sec', async () => {
|
|
10639
|
+
meeting.getPermissionTokenExpiryInfo = sinon
|
|
10640
|
+
.stub()
|
|
10641
|
+
.returns({timeLeft: 9, expiryTime: 122132, currentTime: Date.now()});
|
|
10006
10642
|
meeting.refreshPermissionToken = sinon.stub().returns(Promise.resolve('test return value'));
|
|
10007
10643
|
|
|
10008
10644
|
const returnValue = await meeting.checkAndRefreshPermissionToken(10, 'ttl-join');
|
|
@@ -10013,7 +10649,9 @@ describe('plugin-meetings', () => {
|
|
|
10013
10649
|
});
|
|
10014
10650
|
|
|
10015
10651
|
it('should fire refreshPermissionToken if time left is equal 10sec', async () => {
|
|
10016
|
-
meeting.getPermissionTokenExpiryInfo = sinon
|
|
10652
|
+
meeting.getPermissionTokenExpiryInfo = sinon
|
|
10653
|
+
.stub()
|
|
10654
|
+
.returns({timeLeft: 10, expiryTime: 122132, currentTime: Date.now()});
|
|
10017
10655
|
meeting.refreshPermissionToken = sinon.stub().returns(Promise.resolve('test return value'));
|
|
10018
10656
|
|
|
10019
10657
|
const returnValue = await meeting.checkAndRefreshPermissionToken(10, 'ttl-join');
|
|
@@ -10024,7 +10662,9 @@ describe('plugin-meetings', () => {
|
|
|
10024
10662
|
});
|
|
10025
10663
|
|
|
10026
10664
|
it('should not fire refreshPermissionToken if time left is higher than 10sec', async () => {
|
|
10027
|
-
meeting.getPermissionTokenExpiryInfo = sinon
|
|
10665
|
+
meeting.getPermissionTokenExpiryInfo = sinon
|
|
10666
|
+
.stub()
|
|
10667
|
+
.returns({timeLeft: 11, expiryTime: 122132, currentTime: Date.now()});
|
|
10028
10668
|
meeting.refreshPermissionToken = sinon.stub().returns(Promise.resolve('test return value'));
|
|
10029
10669
|
|
|
10030
10670
|
const returnValue = await meeting.checkAndRefreshPermissionToken(10, 'ttl-join');
|
|
@@ -10037,19 +10677,22 @@ describe('plugin-meetings', () => {
|
|
|
10037
10677
|
|
|
10038
10678
|
describe('#roapMessageReceived', () => {
|
|
10039
10679
|
it('calls roapMessageReceived on the webrtc media connection', () => {
|
|
10040
|
-
const fakeMessage = {
|
|
10680
|
+
const fakeMessage = {messageType: 'fake', sdp: 'fake sdp'};
|
|
10041
10681
|
|
|
10042
10682
|
const getMediaServer = sinon.stub(MeetingsUtil, 'getMediaServer').returns('homer');
|
|
10043
10683
|
|
|
10044
10684
|
meeting.mediaProperties.webrtcMediaConnection = {
|
|
10045
|
-
roapMessageReceived: sinon.stub()
|
|
10685
|
+
roapMessageReceived: sinon.stub(),
|
|
10046
10686
|
};
|
|
10047
10687
|
|
|
10048
10688
|
meeting.roapMessageReceived(fakeMessage);
|
|
10049
10689
|
|
|
10050
|
-
assert.calledOnceWithExactly(
|
|
10690
|
+
assert.calledOnceWithExactly(
|
|
10691
|
+
meeting.mediaProperties.webrtcMediaConnection.roapMessageReceived,
|
|
10692
|
+
fakeMessage
|
|
10693
|
+
);
|
|
10051
10694
|
assert.calledOnceWithExactly(getMediaServer, 'fake sdp');
|
|
10052
10695
|
assert.equal(meeting.mediaProperties.webrtcMediaConnection.mediaServer, 'homer');
|
|
10053
|
-
})
|
|
10054
|
-
})
|
|
10696
|
+
});
|
|
10697
|
+
});
|
|
10055
10698
|
});
|