@webex/plugin-meetings 3.0.0-beta.350 → 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/constants.js +3 -2
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +8 -8
- package/dist/locus-info/index.js.map +1 -1
- package/dist/meeting/index.js +604 -550
- 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/constants.d.ts +2 -1
- package/dist/types/locus-info/index.d.ts +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/constants.ts +2 -1
- package/src/locus-info/index.ts +13 -12
- package/src/meeting/index.ts +142 -107
- package/src/meetings/index.ts +35 -14
- package/test/unit/spec/locus-info/index.js +53 -5
- package/test/unit/spec/meeting/index.js +1736 -1128
- 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
|
-
preferTranscoding: !meeting.isMultistream,
|
|
2798
|
-
ipver: undefined
|
|
2799
|
-
},
|
|
2800
|
-
respOnlySdp: true,
|
|
2801
|
-
usingResource: null,
|
|
2802
|
-
},
|
|
2803
|
-
});
|
|
2804
|
-
};
|
|
2896
|
+
meetingId
|
|
2897
|
+
);
|
|
2805
2898
|
|
|
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
|
-
|
|
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
|
+
);
|
|
2919
|
+
|
|
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});
|
|
2916
|
-
|
|
2917
|
-
// and that these were the only /media requests that were sent
|
|
2918
|
-
assert.calledTwice(locusMediaRequestStub);
|
|
2919
|
-
});
|
|
3040
|
+
it('addMedia() works correctly when media is enabled with tracks to publish and track is muted', async () => {
|
|
3041
|
+
fakeMicrophoneStream.muted = true;
|
|
2920
3042
|
|
|
2921
|
-
|
|
2922
|
-
|
|
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();
|
|
3180
|
+
|
|
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
|
+
});
|
|
3084
3199
|
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
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});
|
|
3088
3204
|
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
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,
|
|
@@ -4316,11 +4485,7 @@ describe('plugin-meetings', () => {
|
|
|
4316
4485
|
);
|
|
4317
4486
|
|
|
4318
4487
|
// parseMeeting info
|
|
4319
|
-
assert.calledWith(
|
|
4320
|
-
meeting.parseMeetingInfo,
|
|
4321
|
-
{body: FAKE_MEETING_INFO, url: FAKE_MEETING_INFO_LOOKUP_URL},
|
|
4322
|
-
FAKE_DESTINATION
|
|
4323
|
-
);
|
|
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
|
);
|
|
@@ -4562,62 +4727,222 @@ describe('plugin-meetings', () => {
|
|
|
4562
4727
|
assert.equal(meeting.requiredCaptcha, null);
|
|
4563
4728
|
});
|
|
4564
4729
|
|
|
4565
|
-
it('refreshes captcha when captcha was required and we received 403 error code', async () => {
|
|
4730
|
+
it('refreshes captcha when captcha was required and we received 403 error code', async () => {
|
|
4731
|
+
meeting.destination = FAKE_DESTINATION;
|
|
4732
|
+
meeting.destinationType = FAKE_TYPE;
|
|
4733
|
+
const refreshedCaptcha = {
|
|
4734
|
+
captchaID: FAKE_WBXAPPAPI_CAPTCHA_INFO.captchaID,
|
|
4735
|
+
verificationImageURL: FAKE_WBXAPPAPI_CAPTCHA_INFO.verificationImageURL,
|
|
4736
|
+
verificationAudioURL: FAKE_WBXAPPAPI_CAPTCHA_INFO.verificationAudioURL,
|
|
4737
|
+
};
|
|
4738
|
+
|
|
4739
|
+
meeting.attrs.meetingInfoProvider = {
|
|
4740
|
+
fetchMeetingInfo: sinon
|
|
4741
|
+
.stub()
|
|
4742
|
+
.throws(new MeetingInfoV2PasswordError(403004, FAKE_MEETING_INFO)),
|
|
4743
|
+
};
|
|
4744
|
+
meeting.meetingRequest.refreshCaptcha = sinon.stub().returns(
|
|
4745
|
+
Promise.resolve({
|
|
4746
|
+
body: refreshedCaptcha,
|
|
4747
|
+
})
|
|
4748
|
+
);
|
|
4749
|
+
meeting.passwordStatus = PASSWORD_STATUS.REQUIRED;
|
|
4750
|
+
meeting.requiredCaptcha = FAKE_SDK_CAPTCHA_INFO;
|
|
4751
|
+
meeting.destination = FAKE_DESTINATION;
|
|
4752
|
+
meeting.destinationType = FAKE_TYPE;
|
|
4753
|
+
|
|
4754
|
+
await assert.isRejected(
|
|
4755
|
+
meeting.fetchMeetingInfo({
|
|
4756
|
+
password: 'aaa',
|
|
4757
|
+
captchaCode: 'bbb',
|
|
4758
|
+
sendCAevents: true,
|
|
4759
|
+
})
|
|
4760
|
+
);
|
|
4761
|
+
|
|
4762
|
+
assert.calledWith(
|
|
4763
|
+
meeting.attrs.meetingInfoProvider.fetchMeetingInfo,
|
|
4764
|
+
FAKE_DESTINATION,
|
|
4765
|
+
FAKE_TYPE,
|
|
4766
|
+
'aaa',
|
|
4767
|
+
{code: 'bbb', id: FAKE_CAPTCHA_ID},
|
|
4768
|
+
undefined,
|
|
4769
|
+
'locus-id',
|
|
4770
|
+
{},
|
|
4771
|
+
{meetingId: meeting.id, sendCAevents: true}
|
|
4772
|
+
);
|
|
4773
|
+
|
|
4774
|
+
assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
|
|
4775
|
+
assert.equal(
|
|
4776
|
+
meeting.meetingInfoFailureReason,
|
|
4777
|
+
MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD
|
|
4778
|
+
);
|
|
4779
|
+
assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
|
|
4780
|
+
assert.deepEqual(meeting.requiredCaptcha, {
|
|
4781
|
+
captchaId: refreshedCaptcha.captchaID,
|
|
4782
|
+
verificationImageURL: refreshedCaptcha.verificationImageURL,
|
|
4783
|
+
verificationAudioURL: refreshedCaptcha.verificationAudioURL,
|
|
4784
|
+
refreshURL: FAKE_SDK_CAPTCHA_INFO.refreshURL, // refresh url doesn't change
|
|
4785
|
+
});
|
|
4786
|
+
});
|
|
4787
|
+
});
|
|
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;
|
|
4566
4885
|
meeting.destination = FAKE_DESTINATION;
|
|
4567
4886
|
meeting.destinationType = FAKE_TYPE;
|
|
4568
|
-
const refreshedCaptcha = {
|
|
4569
|
-
captchaID: FAKE_WBXAPPAPI_CAPTCHA_INFO.captchaID,
|
|
4570
|
-
verificationImageURL: FAKE_WBXAPPAPI_CAPTCHA_INFO.verificationImageURL,
|
|
4571
|
-
verificationAudioURL: FAKE_WBXAPPAPI_CAPTCHA_INFO.verificationAudioURL,
|
|
4572
|
-
};
|
|
4573
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 () => {
|
|
4574
4910
|
meeting.attrs.meetingInfoProvider = {
|
|
4575
|
-
fetchMeetingInfo: sinon
|
|
4576
|
-
.stub()
|
|
4577
|
-
.throws(new MeetingInfoV2PasswordError(403004, FAKE_MEETING_INFO)),
|
|
4911
|
+
fetchMeetingInfo: sinon.stub().resolves(),
|
|
4578
4912
|
};
|
|
4579
|
-
meeting.
|
|
4580
|
-
Promise.resolve({
|
|
4581
|
-
body: refreshedCaptcha,
|
|
4582
|
-
})
|
|
4583
|
-
);
|
|
4584
|
-
meeting.passwordStatus = PASSWORD_STATUS.REQUIRED;
|
|
4585
|
-
meeting.requiredCaptcha = FAKE_SDK_CAPTCHA_INFO;
|
|
4913
|
+
meeting.passwordStatus = PASSWORD_STATUS.NOT_REQUIRED;
|
|
4586
4914
|
meeting.destination = FAKE_DESTINATION;
|
|
4587
4915
|
meeting.destinationType = FAKE_TYPE;
|
|
4588
4916
|
|
|
4589
4917
|
await assert.isRejected(
|
|
4590
|
-
meeting.
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4918
|
+
meeting.injectMeetingInfo(
|
|
4919
|
+
{},
|
|
4920
|
+
{
|
|
4921
|
+
password: FAKE_PASSWORD,
|
|
4922
|
+
}
|
|
4923
|
+
),
|
|
4924
|
+
Error,
|
|
4925
|
+
'injectMeetingInfo() called with password when password was not required'
|
|
4595
4926
|
);
|
|
4596
4927
|
|
|
4597
|
-
assert.
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
{
|
|
4603
|
-
|
|
4604
|
-
'locus-id',
|
|
4605
|
-
{},
|
|
4606
|
-
{meetingId: meeting.id, sendCAevents: true}
|
|
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'
|
|
4607
4935
|
);
|
|
4936
|
+
});
|
|
4608
4937
|
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
|
|
4615
|
-
assert.deepEqual(meeting.requiredCaptcha, {
|
|
4616
|
-
captchaId: refreshedCaptcha.captchaID,
|
|
4617
|
-
verificationImageURL: refreshedCaptcha.verificationImageURL,
|
|
4618
|
-
verificationAudioURL: refreshedCaptcha.verificationAudioURL,
|
|
4619
|
-
refreshURL: FAKE_SDK_CAPTCHA_INFO.refreshURL, // refresh url doesn't change
|
|
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,
|
|
4620
4943
|
});
|
|
4944
|
+
|
|
4945
|
+
assert.equal(meeting.fetchMeetingInfoTimeoutId, undefined);
|
|
4621
4946
|
});
|
|
4622
4947
|
});
|
|
4623
4948
|
|
|
@@ -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();
|
|
@@ -6994,41 +7367,6 @@ describe('plugin-meetings', () => {
|
|
|
6994
7367
|
);
|
|
6995
7368
|
});
|
|
6996
7369
|
|
|
6997
|
-
it('listens to the timing that user joined into breakout', async () => {
|
|
6998
|
-
const mainLocusUrl = 'mainLocusUrl123';
|
|
6999
|
-
|
|
7000
|
-
meeting.meetingRequest.getLocusStatusByUrl = sinon.stub().returns(Promise.resolve());
|
|
7001
|
-
|
|
7002
|
-
await meeting.locusInfo.emit(
|
|
7003
|
-
{function: 'test', file: 'test'},
|
|
7004
|
-
'CONTROLS_JOIN_BREAKOUT_FROM_MAIN',
|
|
7005
|
-
{mainLocusUrl}
|
|
7006
|
-
);
|
|
7007
|
-
|
|
7008
|
-
assert.calledOnceWithExactly(meeting.meetingRequest.getLocusStatusByUrl, mainLocusUrl);
|
|
7009
|
-
const error = {statusCode: 403};
|
|
7010
|
-
meeting.meetingRequest.getLocusStatusByUrl.rejects(error);
|
|
7011
|
-
meeting.locusInfo.clearMainSessionLocusCache = sinon.stub();
|
|
7012
|
-
await meeting.locusInfo.emit(
|
|
7013
|
-
{function: 'test', file: 'test'},
|
|
7014
|
-
'CONTROLS_JOIN_BREAKOUT_FROM_MAIN',
|
|
7015
|
-
{mainLocusUrl}
|
|
7016
|
-
);
|
|
7017
|
-
|
|
7018
|
-
assert.calledOnce(meeting.locusInfo.clearMainSessionLocusCache);
|
|
7019
|
-
|
|
7020
|
-
const otherError = new Error('something wrong');
|
|
7021
|
-
meeting.meetingRequest.getLocusStatusByUrl.rejects(otherError);
|
|
7022
|
-
meeting.locusInfo.clearMainSessionLocusCache = sinon.stub();
|
|
7023
|
-
await meeting.locusInfo.emit(
|
|
7024
|
-
{function: 'test', file: 'test'},
|
|
7025
|
-
'CONTROLS_JOIN_BREAKOUT_FROM_MAIN',
|
|
7026
|
-
{mainLocusUrl}
|
|
7027
|
-
);
|
|
7028
|
-
|
|
7029
|
-
assert.notCalled(meeting.locusInfo.clearMainSessionLocusCache);
|
|
7030
|
-
});
|
|
7031
|
-
|
|
7032
7370
|
it('listens to the locus interpretation update event', () => {
|
|
7033
7371
|
const interpretation = {
|
|
7034
7372
|
siLanguages: [{languageCode: 20, languageName: 'en'}],
|
|
@@ -7156,8 +7494,8 @@ describe('plugin-meetings', () => {
|
|
|
7156
7494
|
newLocusServices.services.webcast.url
|
|
7157
7495
|
);
|
|
7158
7496
|
assert.calledWith(
|
|
7159
|
-
|
|
7160
|
-
|
|
7497
|
+
meeting.webinar.webinarAttendeesSearchingUrlUpdate,
|
|
7498
|
+
newLocusServices.services.webinarAttendeesSearching.url
|
|
7161
7499
|
);
|
|
7162
7500
|
assert.calledOnce(meeting.recordingController.setSessionId);
|
|
7163
7501
|
done();
|
|
@@ -7333,20 +7671,19 @@ describe('plugin-meetings', () => {
|
|
|
7333
7671
|
});
|
|
7334
7672
|
|
|
7335
7673
|
describe('#setPermissionTokenPayload', () => {
|
|
7336
|
-
|
|
7337
7674
|
let now;
|
|
7338
7675
|
let clock;
|
|
7339
|
-
|
|
7676
|
+
|
|
7340
7677
|
beforeEach(() => {
|
|
7341
7678
|
now = Date.now();
|
|
7342
|
-
|
|
7679
|
+
|
|
7343
7680
|
// mock `new Date()` with constant `now`
|
|
7344
7681
|
clock = sinon.useFakeTimers(now);
|
|
7345
7682
|
});
|
|
7346
|
-
|
|
7683
|
+
|
|
7347
7684
|
afterEach(() => {
|
|
7348
7685
|
clock.restore();
|
|
7349
|
-
})
|
|
7686
|
+
});
|
|
7350
7687
|
it('sets correctly', () => {
|
|
7351
7688
|
assert.notOk(meeting.permissionTokenPayload);
|
|
7352
7689
|
|
|
@@ -7368,10 +7705,12 @@ describe('plugin-meetings', () => {
|
|
|
7368
7705
|
|
|
7369
7706
|
const testUrl = 'https://example.com';
|
|
7370
7707
|
|
|
7371
|
-
const policyData = {
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
7708
|
+
const policyData = {
|
|
7709
|
+
permission: {
|
|
7710
|
+
userPolicies: {a: true},
|
|
7711
|
+
enforceVBGImagesURL: testUrl,
|
|
7712
|
+
},
|
|
7713
|
+
};
|
|
7375
7714
|
meeting.permissionTokenPayload = policyData;
|
|
7376
7715
|
|
|
7377
7716
|
meeting.setSelfUserPolicies();
|
|
@@ -7472,8 +7811,11 @@ describe('plugin-meetings', () => {
|
|
|
7472
7811
|
assert.equal(meeting.permissionToken, expectedInfoToParse.permissionToken);
|
|
7473
7812
|
assert.deepEqual(meeting.selfUserPolicies, expectedInfoToParse.selfUserPolicies);
|
|
7474
7813
|
|
|
7475
|
-
if(expectedInfoToParse.permissionTokenPayload) {
|
|
7476
|
-
assert.deepEqual(
|
|
7814
|
+
if (expectedInfoToParse.permissionTokenPayload) {
|
|
7815
|
+
assert.deepEqual(
|
|
7816
|
+
meeting.permissionTokenPayload,
|
|
7817
|
+
expectedInfoToParse.permissionTokenPayload
|
|
7818
|
+
);
|
|
7477
7819
|
}
|
|
7478
7820
|
};
|
|
7479
7821
|
|
|
@@ -7482,12 +7824,12 @@ describe('plugin-meetings', () => {
|
|
|
7482
7824
|
meeting.config.experimental.enableUnifiedMeetings = true;
|
|
7483
7825
|
|
|
7484
7826
|
const expectedPermissionTokenPayload = {
|
|
7485
|
-
exp:
|
|
7827
|
+
exp: '123456',
|
|
7486
7828
|
permission: {
|
|
7487
7829
|
userPolicies: {
|
|
7488
|
-
a: true
|
|
7489
|
-
}
|
|
7490
|
-
}
|
|
7830
|
+
a: true,
|
|
7831
|
+
},
|
|
7832
|
+
},
|
|
7491
7833
|
};
|
|
7492
7834
|
|
|
7493
7835
|
// generated permissionToken with secret `secret` and
|
|
@@ -7496,16 +7838,14 @@ describe('plugin-meetings', () => {
|
|
|
7496
7838
|
'eyJhbGciOiJIUzI1NiJ9.eyJleHAiOiIxMjM0NTYiLCJwZXJtaXNzaW9uIjp7InVzZXJQb2xpY2llcyI6eyJhIjp0cnVlfX19.wkTk0Hp8sUlq2wi2nP4-Ym4Xb7aEUHzyXA1kzk6f0V0';
|
|
7497
7839
|
|
|
7498
7840
|
const FAKE_MEETING_INFO = {
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
owner: test2,
|
|
7508
|
-
},
|
|
7841
|
+
conversationUrl: uuid1,
|
|
7842
|
+
locusUrl: url1,
|
|
7843
|
+
meetingJoinUrl: url2,
|
|
7844
|
+
meetingNumber: '12345',
|
|
7845
|
+
permissionToken,
|
|
7846
|
+
sipMeetingUri: test1,
|
|
7847
|
+
sipUrl: test1,
|
|
7848
|
+
owner: test2,
|
|
7509
7849
|
};
|
|
7510
7850
|
|
|
7511
7851
|
meeting.parseMeetingInfo(FAKE_MEETING_INFO);
|
|
@@ -7519,7 +7859,7 @@ describe('plugin-meetings', () => {
|
|
|
7519
7859
|
owner: test2,
|
|
7520
7860
|
selfUserPolicies: {a: true},
|
|
7521
7861
|
permissionToken,
|
|
7522
|
-
permissionTokenPayload: expectedPermissionTokenPayload
|
|
7862
|
+
permissionTokenPayload: expectedPermissionTokenPayload,
|
|
7523
7863
|
};
|
|
7524
7864
|
|
|
7525
7865
|
checkParseMeetingInfo(expectedInfoToParse);
|
|
@@ -7537,16 +7877,14 @@ describe('plugin-meetings', () => {
|
|
|
7537
7877
|
},
|
|
7538
7878
|
};
|
|
7539
7879
|
const FAKE_MEETING_INFO = {
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
owner: test2,
|
|
7549
|
-
},
|
|
7880
|
+
conversationUrl: uuid1,
|
|
7881
|
+
locusUrl: url1,
|
|
7882
|
+
meetingJoinUrl: url2,
|
|
7883
|
+
meetingNumber: '12345',
|
|
7884
|
+
permissionToken: 'abc',
|
|
7885
|
+
sipMeetingUri: test1,
|
|
7886
|
+
sipUrl: test1,
|
|
7887
|
+
owner: test2,
|
|
7550
7888
|
};
|
|
7551
7889
|
|
|
7552
7890
|
meeting.parseMeetingInfo(FAKE_MEETING_INFO, FAKE_LOCUS_MEETING);
|
|
@@ -7566,16 +7904,14 @@ describe('plugin-meetings', () => {
|
|
|
7566
7904
|
meeting.config.experimental = {enableMediaNegotiatedEvent: true};
|
|
7567
7905
|
meeting.config.experimental.enableUnifiedMeetings = true;
|
|
7568
7906
|
const FAKE_MEETING_INFO = {
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
owner: test2,
|
|
7578
|
-
},
|
|
7907
|
+
conversationUrl: uuid1,
|
|
7908
|
+
locusUrl: url1,
|
|
7909
|
+
meetingJoinUrl: url2,
|
|
7910
|
+
meetingNumber: '12345',
|
|
7911
|
+
permissionToken: 'abc',
|
|
7912
|
+
sipMeetingUri: test1,
|
|
7913
|
+
sipUrl: test1,
|
|
7914
|
+
owner: test2,
|
|
7579
7915
|
};
|
|
7580
7916
|
|
|
7581
7917
|
meeting.parseMeetingInfo(FAKE_MEETING_INFO);
|
|
@@ -7596,16 +7932,14 @@ describe('plugin-meetings', () => {
|
|
|
7596
7932
|
meeting.config.experimental.enableUnifiedMeetings = true;
|
|
7597
7933
|
const FAKE_STRING_DESTINATION = 'sipUrl';
|
|
7598
7934
|
const FAKE_MEETING_INFO = {
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
owner: test2,
|
|
7608
|
-
},
|
|
7935
|
+
conversationUrl: uuid1,
|
|
7936
|
+
locusUrl: url1,
|
|
7937
|
+
meetingJoinUrl: url2,
|
|
7938
|
+
meetingNumber: '12345',
|
|
7939
|
+
permissionToken: 'abc',
|
|
7940
|
+
sipMeetingUri: test1,
|
|
7941
|
+
sipUrl: test1,
|
|
7942
|
+
owner: test2,
|
|
7609
7943
|
};
|
|
7610
7944
|
|
|
7611
7945
|
meeting.parseMeetingInfo(FAKE_MEETING_INFO, FAKE_STRING_DESTINATION);
|
|
@@ -7624,24 +7958,42 @@ describe('plugin-meetings', () => {
|
|
|
7624
7958
|
it('should parse interpretation info correctly', () => {
|
|
7625
7959
|
const parseInterpretationInfo = sinon.spy(MeetingUtil, 'parseInterpretationInfo');
|
|
7626
7960
|
const mockToggleOnData = {
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
],
|
|
7640
|
-
},
|
|
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
|
+
],
|
|
7641
7973
|
},
|
|
7642
7974
|
};
|
|
7643
7975
|
meeting.parseMeetingInfo(mockToggleOnData);
|
|
7644
|
-
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);
|
|
7645
7997
|
});
|
|
7646
7998
|
});
|
|
7647
7999
|
|
|
@@ -8758,7 +9110,6 @@ describe('plugin-meetings', () => {
|
|
|
8758
9110
|
REMOTE_B: 'remote-user-B-url',
|
|
8759
9111
|
};
|
|
8760
9112
|
|
|
8761
|
-
|
|
8762
9113
|
const generateContent = (
|
|
8763
9114
|
beneficiaryId = null,
|
|
8764
9115
|
disposition = null,
|
|
@@ -8767,7 +9118,7 @@ describe('plugin-meetings', () => {
|
|
|
8767
9118
|
) => ({
|
|
8768
9119
|
beneficiaryId,
|
|
8769
9120
|
disposition,
|
|
8770
|
-
deviceUrlSharing
|
|
9121
|
+
deviceUrlSharing,
|
|
8771
9122
|
});
|
|
8772
9123
|
const generateWhiteboard = (
|
|
8773
9124
|
beneficiaryId = null,
|
|
@@ -8786,7 +9137,7 @@ describe('plugin-meetings', () => {
|
|
|
8786
9137
|
annotation,
|
|
8787
9138
|
url,
|
|
8788
9139
|
shareInstanceId,
|
|
8789
|
-
deviceUrlSharing
|
|
9140
|
+
deviceUrlSharing
|
|
8790
9141
|
) => {
|
|
8791
9142
|
const newPayload = cloneDeep(payload);
|
|
8792
9143
|
|
|
@@ -9231,7 +9582,7 @@ describe('plugin-meetings', () => {
|
|
|
9231
9582
|
true,
|
|
9232
9583
|
false,
|
|
9233
9584
|
USER_IDS.ME,
|
|
9234
|
-
RESOURCE_URLS.WHITEBOARD_A
|
|
9585
|
+
RESOURCE_URLS.WHITEBOARD_A
|
|
9235
9586
|
);
|
|
9236
9587
|
const data2 = generateData(
|
|
9237
9588
|
data1.payload,
|
|
@@ -9240,7 +9591,7 @@ describe('plugin-meetings', () => {
|
|
|
9240
9591
|
USER_IDS.ME,
|
|
9241
9592
|
RESOURCE_URLS.WHITEBOARD_A,
|
|
9242
9593
|
true,
|
|
9243
|
-
USER_IDS.ME
|
|
9594
|
+
USER_IDS.ME
|
|
9244
9595
|
);
|
|
9245
9596
|
const data3 = generateData(
|
|
9246
9597
|
data2.payload,
|
|
@@ -9253,9 +9604,21 @@ describe('plugin-meetings', () => {
|
|
|
9253
9604
|
undefined,
|
|
9254
9605
|
undefined,
|
|
9255
9606
|
undefined,
|
|
9256
|
-
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
|
|
9257
9621
|
);
|
|
9258
|
-
const data4 = generateData(data3.payload, false, true, USER_IDS.ME, undefined, undefined, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
|
|
9259
9622
|
|
|
9260
9623
|
payloadTestHelper([data1, data2, data3, data4]);
|
|
9261
9624
|
});
|
|
@@ -9288,7 +9651,7 @@ describe('plugin-meetings', () => {
|
|
|
9288
9651
|
undefined,
|
|
9289
9652
|
undefined,
|
|
9290
9653
|
undefined,
|
|
9291
|
-
DEVICE_URL.REMOTE_A
|
|
9654
|
+
DEVICE_URL.REMOTE_A
|
|
9292
9655
|
);
|
|
9293
9656
|
const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_A);
|
|
9294
9657
|
|
|
@@ -9323,9 +9686,21 @@ describe('plugin-meetings', () => {
|
|
|
9323
9686
|
undefined,
|
|
9324
9687
|
undefined,
|
|
9325
9688
|
undefined,
|
|
9326
|
-
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
|
|
9327
9703
|
);
|
|
9328
|
-
const data4 = generateData(data3.payload, false, true, USER_IDS.ME, undefined, undefined, undefined, undefined, undefined, undefined, DEVICE_URL.LOCAL_WEB);
|
|
9329
9704
|
|
|
9330
9705
|
payloadTestHelper([data1, data2, data3, data4]);
|
|
9331
9706
|
});
|
|
@@ -9358,7 +9733,7 @@ describe('plugin-meetings', () => {
|
|
|
9358
9733
|
undefined,
|
|
9359
9734
|
undefined,
|
|
9360
9735
|
undefined,
|
|
9361
|
-
DEVICE_URL.REMOTE_A
|
|
9736
|
+
DEVICE_URL.REMOTE_A
|
|
9362
9737
|
);
|
|
9363
9738
|
const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_A);
|
|
9364
9739
|
|
|
@@ -9393,7 +9768,7 @@ describe('plugin-meetings', () => {
|
|
|
9393
9768
|
undefined,
|
|
9394
9769
|
undefined,
|
|
9395
9770
|
undefined,
|
|
9396
|
-
DEVICE_URL.REMOTE_B
|
|
9771
|
+
DEVICE_URL.REMOTE_B
|
|
9397
9772
|
);
|
|
9398
9773
|
const data4 = generateData(data3.payload, false, true, USER_IDS.REMOTE_B);
|
|
9399
9774
|
|
|
@@ -9403,7 +9778,19 @@ describe('plugin-meetings', () => {
|
|
|
9403
9778
|
|
|
9404
9779
|
describe('Desktop --> Whiteboard A', () => {
|
|
9405
9780
|
it('Scenario #1: you share desktop and then share whiteboard', () => {
|
|
9406
|
-
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
|
+
);
|
|
9407
9794
|
const data2 = generateData(
|
|
9408
9795
|
data1.payload,
|
|
9409
9796
|
true,
|
|
@@ -9417,7 +9804,19 @@ describe('plugin-meetings', () => {
|
|
|
9417
9804
|
});
|
|
9418
9805
|
|
|
9419
9806
|
it('Scenario #2: you share desktop and remote person A shares whiteboard', () => {
|
|
9420
|
-
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
|
+
);
|
|
9421
9820
|
const data2 = generateData(
|
|
9422
9821
|
data1.payload,
|
|
9423
9822
|
true,
|
|
@@ -9431,7 +9830,19 @@ describe('plugin-meetings', () => {
|
|
|
9431
9830
|
});
|
|
9432
9831
|
|
|
9433
9832
|
it('Scenario #3: remote person A shares desktop and you share whiteboard', () => {
|
|
9434
|
-
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
|
+
);
|
|
9435
9846
|
const data2 = generateData(
|
|
9436
9847
|
data1.payload,
|
|
9437
9848
|
true,
|
|
@@ -9445,7 +9856,19 @@ describe('plugin-meetings', () => {
|
|
|
9445
9856
|
});
|
|
9446
9857
|
|
|
9447
9858
|
it('Scenario #4: remote person A shares desktop and then shares whiteboard', () => {
|
|
9448
|
-
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
|
+
);
|
|
9449
9872
|
const data2 = generateData(
|
|
9450
9873
|
data1.payload,
|
|
9451
9874
|
true,
|
|
@@ -9459,7 +9882,19 @@ describe('plugin-meetings', () => {
|
|
|
9459
9882
|
});
|
|
9460
9883
|
|
|
9461
9884
|
it('Scenario #5: remote person A shares desktop and remote person B shares whiteboard', () => {
|
|
9462
|
-
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
|
+
);
|
|
9463
9898
|
const data2 = generateData(
|
|
9464
9899
|
data1.payload,
|
|
9465
9900
|
true,
|
|
@@ -9474,26 +9909,146 @@ describe('plugin-meetings', () => {
|
|
|
9474
9909
|
});
|
|
9475
9910
|
describe('Desktop A --> Desktop B', () => {
|
|
9476
9911
|
it('Scenario #1: you share desktop using web client and then share using native client', () => {
|
|
9477
|
-
const data1 = generateData(
|
|
9478
|
-
|
|
9479
|
-
|
|
9480
|
-
|
|
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
|
+
);
|
|
9481
9964
|
|
|
9482
9965
|
payloadTestHelper([data1, data2, data3, data4]);
|
|
9483
9966
|
});
|
|
9484
9967
|
|
|
9485
9968
|
it('Scenario #2: you share desktop using web client and remote person A shares desktop', () => {
|
|
9486
|
-
const data1 = generateData(
|
|
9487
|
-
|
|
9488
|
-
|
|
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
|
+
);
|
|
9489
10008
|
|
|
9490
10009
|
payloadTestHelper([data1, data2, data3]);
|
|
9491
10010
|
});
|
|
9492
10011
|
|
|
9493
10012
|
it('Scenario #3: remote person A shares desktop and then you share desktop using web client', () => {
|
|
9494
|
-
const data1 = generateData(
|
|
9495
|
-
|
|
9496
|
-
|
|
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
|
+
);
|
|
9497
10052
|
|
|
9498
10053
|
payloadTestHelper([data1, data2, data3]);
|
|
9499
10054
|
});
|
|
@@ -9507,8 +10062,32 @@ describe('plugin-meetings', () => {
|
|
|
9507
10062
|
});
|
|
9508
10063
|
|
|
9509
10064
|
it('Scenario #5: remote person A shares desktop A and remote person B shares desktop B', () => {
|
|
9510
|
-
const data1 = generateData(
|
|
9511
|
-
|
|
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
|
+
);
|
|
9512
10091
|
const data3 = generateData(data2.payload, false, true, USER_IDS.REMOTE_B);
|
|
9513
10092
|
|
|
9514
10093
|
payloadTestHelper([data1, data2, data3]);
|
|
@@ -9927,26 +10506,34 @@ describe('plugin-meetings', () => {
|
|
|
9927
10506
|
|
|
9928
10507
|
afterEach(() => {
|
|
9929
10508
|
clock.restore();
|
|
9930
|
-
})
|
|
10509
|
+
});
|
|
9931
10510
|
|
|
9932
10511
|
it('should return undefined if exp is undefined', () => {
|
|
9933
|
-
assert.equal(meeting.getPermissionTokenExpiryInfo(), undefined)
|
|
10512
|
+
assert.equal(meeting.getPermissionTokenExpiryInfo(), undefined);
|
|
9934
10513
|
});
|
|
9935
10514
|
|
|
9936
10515
|
it('should return the expected positive exp', () => {
|
|
9937
10516
|
// set permission token as now + 1 sec
|
|
9938
10517
|
const expiryTime = now + 1000;
|
|
9939
|
-
meeting.permissionTokenPayload = {exp:
|
|
10518
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: now};
|
|
9940
10519
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
9941
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10520
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10521
|
+
timeLeft: 1,
|
|
10522
|
+
expiryTime: Number(expiryTime),
|
|
10523
|
+
currentTime: now,
|
|
10524
|
+
});
|
|
9942
10525
|
});
|
|
9943
10526
|
|
|
9944
10527
|
it('should return the expected negative exp', () => {
|
|
9945
10528
|
// set permission token as now - 1 sec
|
|
9946
10529
|
const expiryTime = now - 1000;
|
|
9947
|
-
meeting.permissionTokenPayload = {exp:
|
|
10530
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: now};
|
|
9948
10531
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
9949
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10532
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10533
|
+
timeLeft: -1,
|
|
10534
|
+
expiryTime: Number(expiryTime),
|
|
10535
|
+
currentTime: now,
|
|
10536
|
+
});
|
|
9950
10537
|
});
|
|
9951
10538
|
|
|
9952
10539
|
describe('#getPermissionTokenExpiryInfo with wrong current time which is in future', () => {
|
|
@@ -9955,34 +10542,41 @@ describe('plugin-meetings', () => {
|
|
|
9955
10542
|
beforeEach(() => {
|
|
9956
10543
|
// current time is 3 hours off
|
|
9957
10544
|
now = Date.now() + 10800000;
|
|
9958
|
-
|
|
10545
|
+
|
|
9959
10546
|
// mock `new Date()` with constant `now`
|
|
9960
10547
|
clock = sinon.useFakeTimers(now);
|
|
9961
10548
|
});
|
|
9962
|
-
|
|
10549
|
+
|
|
9963
10550
|
afterEach(() => {
|
|
9964
10551
|
clock.restore();
|
|
9965
|
-
})
|
|
9966
|
-
|
|
10552
|
+
});
|
|
10553
|
+
|
|
9967
10554
|
it('should return the expected positive exp when client time is wrong', () => {
|
|
9968
10555
|
const serverTime = Date.now();
|
|
9969
|
-
|
|
9970
|
-
|
|
10556
|
+
|
|
10557
|
+
// set permission token as now + 1 sec
|
|
9971
10558
|
const expiryTime = serverTime + 1000;
|
|
9972
|
-
meeting.permissionTokenPayload = {exp:
|
|
10559
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: serverTime};
|
|
9973
10560
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
9974
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10561
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10562
|
+
timeLeft: 1,
|
|
10563
|
+
expiryTime: Number(expiryTime),
|
|
10564
|
+
currentTime: now,
|
|
10565
|
+
});
|
|
9975
10566
|
});
|
|
9976
|
-
|
|
10567
|
+
|
|
9977
10568
|
it('should return the expected negative exp when client time is wrong', () => {
|
|
9978
10569
|
const serverTime = Date.now();
|
|
9979
10570
|
// set permission token as now - 1 sec
|
|
9980
10571
|
const expiryTime = serverTime - 1000;
|
|
9981
|
-
meeting.permissionTokenPayload = {exp:
|
|
10572
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: serverTime};
|
|
9982
10573
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
9983
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10574
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10575
|
+
timeLeft: -1,
|
|
10576
|
+
expiryTime: Number(expiryTime),
|
|
10577
|
+
currentTime: now,
|
|
10578
|
+
});
|
|
9984
10579
|
});
|
|
9985
|
-
|
|
9986
10580
|
});
|
|
9987
10581
|
|
|
9988
10582
|
describe('#getPermissionTokenExpiryInfo with wrong current Time which is in the past', () => {
|
|
@@ -9991,42 +10585,47 @@ describe('plugin-meetings', () => {
|
|
|
9991
10585
|
beforeEach(() => {
|
|
9992
10586
|
// current time is 3 hours off
|
|
9993
10587
|
now = Date.now() - 10800000;
|
|
9994
|
-
|
|
10588
|
+
|
|
9995
10589
|
// mock `new Date()` with constant `now`
|
|
9996
10590
|
clock = sinon.useFakeTimers(now);
|
|
9997
10591
|
});
|
|
9998
|
-
|
|
10592
|
+
|
|
9999
10593
|
afterEach(() => {
|
|
10000
10594
|
clock.restore();
|
|
10001
|
-
})
|
|
10002
|
-
|
|
10595
|
+
});
|
|
10596
|
+
|
|
10003
10597
|
it('should return the expected positive exp when client time is wrong', () => {
|
|
10004
10598
|
const serverTime = Date.now();
|
|
10005
|
-
|
|
10006
|
-
|
|
10599
|
+
|
|
10600
|
+
// set permission token as now + 1 sec
|
|
10007
10601
|
const expiryTime = serverTime + 1000;
|
|
10008
|
-
meeting.permissionTokenPayload = {exp:
|
|
10602
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: serverTime};
|
|
10009
10603
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
10010
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10604
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10605
|
+
timeLeft: 1,
|
|
10606
|
+
expiryTime: Number(expiryTime),
|
|
10607
|
+
currentTime: now,
|
|
10608
|
+
});
|
|
10011
10609
|
});
|
|
10012
|
-
|
|
10610
|
+
|
|
10013
10611
|
it('should return the expected negative exp when client time is wrong', () => {
|
|
10014
10612
|
const serverTime = Date.now();
|
|
10015
10613
|
// set permission token as now - 1 sec
|
|
10016
10614
|
const expiryTime = serverTime - 1000;
|
|
10017
|
-
meeting.permissionTokenPayload = {exp:
|
|
10615
|
+
meeting.permissionTokenPayload = {exp: expiryTime.toString(), iat: serverTime};
|
|
10018
10616
|
meeting.permissionTokenReceivedLocalTime = now;
|
|
10019
|
-
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10617
|
+
assert.deepEqual(meeting.getPermissionTokenExpiryInfo(), {
|
|
10618
|
+
timeLeft: -1,
|
|
10619
|
+
expiryTime: Number(expiryTime),
|
|
10620
|
+
currentTime: now,
|
|
10621
|
+
});
|
|
10020
10622
|
});
|
|
10021
|
-
|
|
10022
10623
|
});
|
|
10023
10624
|
});
|
|
10024
10625
|
|
|
10025
|
-
|
|
10026
|
-
|
|
10027
10626
|
describe('#checkAndRefreshPermissionToken', () => {
|
|
10028
|
-
it('should not fire refreshPermissionToken if permissionToken is not defined', async() => {
|
|
10029
|
-
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);
|
|
10030
10629
|
meeting.refreshPermissionToken = sinon.stub().returns(Promise.resolve('test return value'));
|
|
10031
10630
|
|
|
10032
10631
|
const returnValue = await meeting.checkAndRefreshPermissionToken(10, 'ttl-join');
|
|
@@ -10036,8 +10635,10 @@ describe('plugin-meetings', () => {
|
|
|
10036
10635
|
assert.equal(returnValue, undefined);
|
|
10037
10636
|
});
|
|
10038
10637
|
|
|
10039
|
-
it('should fire refreshPermissionToken if time left is below 10sec', async() => {
|
|
10040
|
-
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()});
|
|
10041
10642
|
meeting.refreshPermissionToken = sinon.stub().returns(Promise.resolve('test return value'));
|
|
10042
10643
|
|
|
10043
10644
|
const returnValue = await meeting.checkAndRefreshPermissionToken(10, 'ttl-join');
|
|
@@ -10048,7 +10649,9 @@ describe('plugin-meetings', () => {
|
|
|
10048
10649
|
});
|
|
10049
10650
|
|
|
10050
10651
|
it('should fire refreshPermissionToken if time left is equal 10sec', async () => {
|
|
10051
|
-
meeting.getPermissionTokenExpiryInfo = sinon
|
|
10652
|
+
meeting.getPermissionTokenExpiryInfo = sinon
|
|
10653
|
+
.stub()
|
|
10654
|
+
.returns({timeLeft: 10, expiryTime: 122132, currentTime: Date.now()});
|
|
10052
10655
|
meeting.refreshPermissionToken = sinon.stub().returns(Promise.resolve('test return value'));
|
|
10053
10656
|
|
|
10054
10657
|
const returnValue = await meeting.checkAndRefreshPermissionToken(10, 'ttl-join');
|
|
@@ -10059,7 +10662,9 @@ describe('plugin-meetings', () => {
|
|
|
10059
10662
|
});
|
|
10060
10663
|
|
|
10061
10664
|
it('should not fire refreshPermissionToken if time left is higher than 10sec', async () => {
|
|
10062
|
-
meeting.getPermissionTokenExpiryInfo = sinon
|
|
10665
|
+
meeting.getPermissionTokenExpiryInfo = sinon
|
|
10666
|
+
.stub()
|
|
10667
|
+
.returns({timeLeft: 11, expiryTime: 122132, currentTime: Date.now()});
|
|
10063
10668
|
meeting.refreshPermissionToken = sinon.stub().returns(Promise.resolve('test return value'));
|
|
10064
10669
|
|
|
10065
10670
|
const returnValue = await meeting.checkAndRefreshPermissionToken(10, 'ttl-join');
|
|
@@ -10072,19 +10677,22 @@ describe('plugin-meetings', () => {
|
|
|
10072
10677
|
|
|
10073
10678
|
describe('#roapMessageReceived', () => {
|
|
10074
10679
|
it('calls roapMessageReceived on the webrtc media connection', () => {
|
|
10075
|
-
const fakeMessage = {
|
|
10680
|
+
const fakeMessage = {messageType: 'fake', sdp: 'fake sdp'};
|
|
10076
10681
|
|
|
10077
10682
|
const getMediaServer = sinon.stub(MeetingsUtil, 'getMediaServer').returns('homer');
|
|
10078
10683
|
|
|
10079
10684
|
meeting.mediaProperties.webrtcMediaConnection = {
|
|
10080
|
-
roapMessageReceived: sinon.stub()
|
|
10685
|
+
roapMessageReceived: sinon.stub(),
|
|
10081
10686
|
};
|
|
10082
10687
|
|
|
10083
10688
|
meeting.roapMessageReceived(fakeMessage);
|
|
10084
10689
|
|
|
10085
|
-
assert.calledOnceWithExactly(
|
|
10690
|
+
assert.calledOnceWithExactly(
|
|
10691
|
+
meeting.mediaProperties.webrtcMediaConnection.roapMessageReceived,
|
|
10692
|
+
fakeMessage
|
|
10693
|
+
);
|
|
10086
10694
|
assert.calledOnceWithExactly(getMediaServer, 'fake sdp');
|
|
10087
10695
|
assert.equal(meeting.mediaProperties.webrtcMediaConnection.mediaServer, 'homer');
|
|
10088
|
-
})
|
|
10089
|
-
})
|
|
10696
|
+
});
|
|
10697
|
+
});
|
|
10090
10698
|
});
|