@webex/plugin-meetings 1.145.1 → 1.147.1
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/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +5 -3
- package/dist/constants.js.map +1 -1
- package/dist/media/index.js +16 -8
- package/dist/media/index.js.map +1 -1
- package/dist/meeting/index.js +19 -2
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/util.js +4 -12
- package/dist/meeting/util.js.map +1 -1
- package/dist/members/index.js +63 -0
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js +41 -0
- package/dist/members/request.js.map +1 -1
- package/dist/members/util.js +59 -0
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/index.js +0 -2
- package/dist/metrics/index.js.map +1 -1
- package/dist/peer-connection-manager/index.js +8 -7
- package/dist/peer-connection-manager/index.js.map +1 -1
- package/dist/reconnection-manager/index.js +2 -1
- package/dist/reconnection-manager/index.js.map +1 -1
- package/package.json +5 -5
- package/src/config.js +1 -0
- package/src/constants.js +2 -1
- package/src/media/index.js +58 -10
- package/src/meeting/index.js +17 -2
- package/src/meeting/util.js +3 -16
- package/src/members/index.js +56 -0
- package/src/members/request.js +35 -0
- package/src/members/util.js +58 -1
- package/src/metrics/index.js +0 -2
- package/src/peer-connection-manager/index.js +13 -9
- package/src/reconnection-manager/index.js +2 -1
- package/test/unit/spec/meeting/index.js +16 -0
- package/test/unit/spec/members/index.js +192 -0
- package/test/unit/spec/members/request.js +101 -0
|
@@ -186,7 +186,6 @@ pc.iceCandidate = (peerConnection, {remoteQualityLevel}) =>
|
|
|
186
186
|
const timeout = setTimeout(() => {
|
|
187
187
|
peerConnection.sdp = limitBandwidth(peerConnection.localDescription.sdp);
|
|
188
188
|
peerConnection.sdp = setMaxFs(peerConnection.sdp, remoteQualityLevel);
|
|
189
|
-
peerConnection.sdp = peerConnection.sdp.replace(/\na=extmap.*/g, '');
|
|
190
189
|
|
|
191
190
|
if (isSdpInvalid(peerConnection.sdp)) {
|
|
192
191
|
setTimeout(() => {
|
|
@@ -214,7 +213,6 @@ pc.iceCandidate = (peerConnection, {remoteQualityLevel}) =>
|
|
|
214
213
|
if (!evt.candidate && !peerConnection.sdp) {
|
|
215
214
|
peerConnection.sdp = limitBandwidth(peerConnection.localDescription.sdp);
|
|
216
215
|
peerConnection.sdp = setMaxFs(peerConnection.sdp, remoteQualityLevel);
|
|
217
|
-
peerConnection.sdp = peerConnection.sdp.replace(/\na=extmap.*/g, '');
|
|
218
216
|
|
|
219
217
|
if (evt.candidate === null && !isSdpInvalid(peerConnection.sdp)) {
|
|
220
218
|
clearTimeout(timeout);
|
|
@@ -292,9 +290,7 @@ pc.addStream = (peerConnection, stream) => {
|
|
|
292
290
|
*/
|
|
293
291
|
pc.setRemoteSessionDetails = (peerConnection, typeStr, remoteSdp, meetingId) => {
|
|
294
292
|
LoggerProxy.logger.log(`PeerConnectionManager:index#setRemoteSessionDetails --> Setting the remote description type: ${typeStr}State: ${peerConnection.signalingState}`);
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
sdp = sdp.replace(/\na=extmap.*/g, '');
|
|
293
|
+
const sdp = remoteSdp;
|
|
298
294
|
|
|
299
295
|
// making sure that the remoteDescription is only set when there is a answer for offer
|
|
300
296
|
// or there is a offer from the server
|
|
@@ -363,9 +359,15 @@ pc.setRemoteSessionDetails = (peerConnection, typeStr, remoteSdp, meetingId) =>
|
|
|
363
359
|
* @param {string} meetingProperties.meetingId
|
|
364
360
|
* @param {string} meetingProperties.remoteQualityLevel LOW|MEDIUM|HIGH
|
|
365
361
|
* @param {string} meetingProperties.enableRtx
|
|
362
|
+
* @param {string} meetingProperties.enableExtmap
|
|
366
363
|
* @returns {RTCPeerConnection}
|
|
367
364
|
*/
|
|
368
|
-
pc.createOffer = (peerConnection, {
|
|
365
|
+
pc.createOffer = (peerConnection, {
|
|
366
|
+
meetingId,
|
|
367
|
+
remoteQualityLevel,
|
|
368
|
+
enableRtx,
|
|
369
|
+
enableExtmap
|
|
370
|
+
}) => {
|
|
369
371
|
LoggerProxy.logger.log('PeerConnectionManager:index#createOffer --> creating a new offer');
|
|
370
372
|
|
|
371
373
|
return peerConnection
|
|
@@ -389,7 +391,11 @@ pc.createOffer = (peerConnection, {meetingId, remoteQualityLevel, enableRtx}) =>
|
|
|
389
391
|
if (!checkH264Support(peerConnection.sdp)) {
|
|
390
392
|
throw new MediaError('openH264 is downloading please Wait. Upload logs if not working on second try');
|
|
391
393
|
}
|
|
392
|
-
|
|
394
|
+
|
|
395
|
+
if (!enableExtmap) {
|
|
396
|
+
peerConnection.sdp = peerConnection.sdp.replace(/\na=extmap.*/g, '');
|
|
397
|
+
}
|
|
398
|
+
|
|
393
399
|
pc.setContentSlides(peerConnection);
|
|
394
400
|
|
|
395
401
|
Metrics.postEvent({
|
|
@@ -512,8 +518,6 @@ pc.createAnswer = (params, {meetingId, remoteQualityLevel}) => {
|
|
|
512
518
|
throw new MediaError('openH264 is downloading please Wait. Upload logs if not working on second try');
|
|
513
519
|
}
|
|
514
520
|
|
|
515
|
-
peerConnection.sdp = peerConnection.sdp.replace(/\na=extmap.*/g, '');
|
|
516
|
-
|
|
517
521
|
return peerConnection;
|
|
518
522
|
})
|
|
519
523
|
.catch((error) => {
|
|
@@ -459,7 +459,8 @@ export default class ReconnectionManager {
|
|
|
459
459
|
return Media.attachMedia(this.meeting.mediaProperties, {
|
|
460
460
|
meetingId: this.meeting.id,
|
|
461
461
|
remoteQualityLevel: this.meeting.mediaProperties.remoteQualityLevel,
|
|
462
|
-
enableRtx: this.meeting.config.enableRtx
|
|
462
|
+
enableRtx: this.meeting.config.enableRtx,
|
|
463
|
+
enableExtmap: this.meeting.config.enableExtmap
|
|
463
464
|
})
|
|
464
465
|
.then((peerConnection) => this.meeting.setRemoteStream(peerConnection))
|
|
465
466
|
.then(() => {
|
|
@@ -186,6 +186,22 @@ describe('plugin-meetings', () => {
|
|
|
186
186
|
assert.calledWith(meeting.members.addMember, uuid1, false);
|
|
187
187
|
});
|
|
188
188
|
});
|
|
189
|
+
describe('#cancelPhoneInvite', () => {
|
|
190
|
+
it('should have #invite', () => {
|
|
191
|
+
assert.exists(meeting.cancelPhoneInvite);
|
|
192
|
+
});
|
|
193
|
+
beforeEach(() => {
|
|
194
|
+
meeting.members.cancelPhoneInvite = sinon.stub().returns(Promise.resolve(test1));
|
|
195
|
+
});
|
|
196
|
+
it('should proxy members #cancelPhoneInvite and return a promise', async () => {
|
|
197
|
+
const cancel = meeting.cancelPhoneInvite(uuid1);
|
|
198
|
+
|
|
199
|
+
assert.exists(cancel.then);
|
|
200
|
+
await cancel;
|
|
201
|
+
assert.calledOnce(meeting.members.cancelPhoneInvite);
|
|
202
|
+
assert.calledWith(meeting.members.cancelPhoneInvite, uuid1);
|
|
203
|
+
});
|
|
204
|
+
});
|
|
189
205
|
describe('#admit', () => {
|
|
190
206
|
it('should have #admit', () => {
|
|
191
207
|
assert.exists(meeting.admit);
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import sinon from 'sinon';
|
|
6
|
+
import uuid from 'uuid';
|
|
7
|
+
import chai from 'chai';
|
|
8
|
+
import chaiAsPromised from 'chai-as-promised';
|
|
9
|
+
import {Credentials} from '@webex/webex-core';
|
|
10
|
+
import Support from '@webex/internal-plugin-support';
|
|
11
|
+
import MockWebex from '@webex/test-helper-mock-webex';
|
|
12
|
+
import Meetings from '@webex/plugin-meetings';
|
|
13
|
+
import Members from '@webex/plugin-meetings/src/members';
|
|
14
|
+
import MembersUtil from '@webex/plugin-meetings/src/members/util';
|
|
15
|
+
|
|
16
|
+
const {assert} = chai;
|
|
17
|
+
|
|
18
|
+
chai.use(chaiAsPromised);
|
|
19
|
+
sinon.assert.expose(chai.assert, {prefix: ''});
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
describe('plugin-meetings', () => {
|
|
23
|
+
let webex;
|
|
24
|
+
let url1;
|
|
25
|
+
const fakeMembersCollection = {
|
|
26
|
+
test1: {
|
|
27
|
+
namespace: 'Meetings',
|
|
28
|
+
participant: {
|
|
29
|
+
state: 'JOINED',
|
|
30
|
+
type: 'USER',
|
|
31
|
+
person: {
|
|
32
|
+
id: '6eb08f8b-bf69-3251-a126-b161bead2d21',
|
|
33
|
+
phoneNumber: '+18578675309',
|
|
34
|
+
isExternal: true,
|
|
35
|
+
primaryDisplayString: '+18578675309'
|
|
36
|
+
},
|
|
37
|
+
devices: [
|
|
38
|
+
{
|
|
39
|
+
url: 'https://fakeURL.com',
|
|
40
|
+
deviceType: 'SIP',
|
|
41
|
+
state: 'JOINED',
|
|
42
|
+
intents: [
|
|
43
|
+
null
|
|
44
|
+
],
|
|
45
|
+
correlationId: '1234',
|
|
46
|
+
provisionalUrl: 'dialout:///fake',
|
|
47
|
+
isSparkPstn: true
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
url: 'dialout:///fakeagain',
|
|
51
|
+
deviceType: 'PROVISIONAL',
|
|
52
|
+
state: 'JOINED',
|
|
53
|
+
intents: [
|
|
54
|
+
null
|
|
55
|
+
],
|
|
56
|
+
correlationId: '4321',
|
|
57
|
+
isVideoCallback: false,
|
|
58
|
+
clientUrl: 'https://fakeURL',
|
|
59
|
+
provisionalType: 'DIAL_OUT_ONLY',
|
|
60
|
+
dialingStatus: 'SUCCESS'
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
status: {
|
|
64
|
+
audioStatus: 'SENDRECV',
|
|
65
|
+
videoStatus: 'INACTIVE'
|
|
66
|
+
},
|
|
67
|
+
id: 'abc-123-abc-123',
|
|
68
|
+
guest: true,
|
|
69
|
+
resourceGuest: false,
|
|
70
|
+
moderator: false,
|
|
71
|
+
panelist: false,
|
|
72
|
+
moveToLobbyNotAllowed: true,
|
|
73
|
+
deviceUrl: 'https://fakeDeviceurl'
|
|
74
|
+
},
|
|
75
|
+
id: 'abc-123-abc-123',
|
|
76
|
+
status: 'IN_MEETING',
|
|
77
|
+
type: 'MEETING',
|
|
78
|
+
isModerator: false
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
describe('members', () => {
|
|
84
|
+
const sandbox = sinon.createSandbox();
|
|
85
|
+
let createMembers;
|
|
86
|
+
|
|
87
|
+
beforeEach(() => {
|
|
88
|
+
webex = new MockWebex({
|
|
89
|
+
children: {
|
|
90
|
+
meetings: Meetings,
|
|
91
|
+
credentials: Credentials,
|
|
92
|
+
support: Support
|
|
93
|
+
},
|
|
94
|
+
config: {
|
|
95
|
+
credentials: {
|
|
96
|
+
client_id: 'mock-client-id'
|
|
97
|
+
},
|
|
98
|
+
meetings: {
|
|
99
|
+
reconnection: {
|
|
100
|
+
enabled: false
|
|
101
|
+
},
|
|
102
|
+
mediaSettings: {},
|
|
103
|
+
metrics: {},
|
|
104
|
+
stats: {}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
url1 = `https://example.com/${uuid.v4()}`;
|
|
110
|
+
|
|
111
|
+
createMembers = (options) => new Members({locusUrl: options.url}, {parent: webex});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
afterEach(() => {
|
|
115
|
+
sandbox.restore();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('#addMembers', () => {
|
|
119
|
+
it('should invoke isInvalidInvitee and generateAddMemberOptions from MembersUtil when addMember is called with valid params', async () => {
|
|
120
|
+
sandbox.spy(MembersUtil, 'isInvalidInvitee');
|
|
121
|
+
sandbox.spy(MembersUtil, 'generateAddMemberOptions');
|
|
122
|
+
|
|
123
|
+
const members = createMembers({url: url1});
|
|
124
|
+
|
|
125
|
+
await members.addMember({phoneNumber: '+18578675309'});
|
|
126
|
+
assert.calledOnce(MembersUtil.isInvalidInvitee);
|
|
127
|
+
assert.calledOnce(MembersUtil.generateAddMemberOptions);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should throw a rejection if there is no locus url', async () => {
|
|
131
|
+
const members = createMembers({url: false});
|
|
132
|
+
|
|
133
|
+
assert.isRejected(members.addMember({email: 'test@cisco.com'}));
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe('#sendDialPadKey', () => {
|
|
138
|
+
it('should throw a rejection when calling sendDialPadKey with no tones', async () => {
|
|
139
|
+
const members = createMembers({url: url1});
|
|
140
|
+
|
|
141
|
+
assert.isRejected(members.sendDialPadKey());
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should throw a rejection when calling sendDialPadKey with no member is found', async () => {
|
|
145
|
+
const members = createMembers({url: url1});
|
|
146
|
+
|
|
147
|
+
assert.isRejected(members.sendDialPadKey('1', '1234'));
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should call genderateSendDTMFOptions with proper options on Members util if we the member is valid', async () => {
|
|
151
|
+
sandbox.spy(MembersUtil, 'genderateSendDTMFOptions');
|
|
152
|
+
const members = createMembers({url: url1});
|
|
153
|
+
|
|
154
|
+
members.membersCollection.setAll(fakeMembersCollection);
|
|
155
|
+
await members.sendDialPadKey('1', 'test1');
|
|
156
|
+
assert.calledWith(MembersUtil.genderateSendDTMFOptions, 'https://fakeURL.com', '1', 'test1', url1);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should call the sendDialPadKey method on membersRequest if the member is valid', async () => {
|
|
160
|
+
const members = createMembers({url: url1});
|
|
161
|
+
|
|
162
|
+
const {membersRequest} = members;
|
|
163
|
+
|
|
164
|
+
assert.exists(membersRequest);
|
|
165
|
+
const sendDialPadKeyspy = sandbox.spy(membersRequest, 'sendDialPadKey');
|
|
166
|
+
|
|
167
|
+
members.membersCollection.setAll(fakeMembersCollection);
|
|
168
|
+
await members.sendDialPadKey('1', 'test1');
|
|
169
|
+
assert.calledOnce(sendDialPadKeyspy);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe('#cancelPhoneInvite', () => {
|
|
174
|
+
it('should invoke isInvalidInvitee and generateAddMemberOptions from MembersUtil when addMember is called with valid params', async () => {
|
|
175
|
+
sandbox.spy(MembersUtil, 'isInvalidInvitee');
|
|
176
|
+
sandbox.spy(MembersUtil, 'cancelPhoneInviteOptions');
|
|
177
|
+
|
|
178
|
+
const members = createMembers({url: url1});
|
|
179
|
+
|
|
180
|
+
await members.cancelPhoneInvite({phoneNumber: '+18578675309'});
|
|
181
|
+
assert.calledOnce(MembersUtil.isInvalidInvitee);
|
|
182
|
+
assert.calledOnce(MembersUtil.cancelPhoneInviteOptions);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('should throw a rejection if there is no locus url', async () => {
|
|
186
|
+
const members = createMembers({url: false});
|
|
187
|
+
|
|
188
|
+
assert.isRejected(members.cancelPhoneInvite({phoneNumber: '+18578675309'}));
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import sinon from 'sinon';
|
|
2
|
+
import chai from 'chai';
|
|
3
|
+
import uuid from 'uuid';
|
|
4
|
+
import chaiAsPromised from 'chai-as-promised';
|
|
5
|
+
import MockWebex from '@webex/test-helper-mock-webex';
|
|
6
|
+
import Meetings from '@webex/plugin-meetings';
|
|
7
|
+
import MembersRequest from '@webex/plugin-meetings/src/members/request';
|
|
8
|
+
|
|
9
|
+
const {assert} = chai;
|
|
10
|
+
|
|
11
|
+
chai.use(chaiAsPromised);
|
|
12
|
+
sinon.assert.expose(chai.assert, {prefix: ''});
|
|
13
|
+
|
|
14
|
+
describe('plugin-meetings', () => {
|
|
15
|
+
let membersRequest;
|
|
16
|
+
let url1;
|
|
17
|
+
let sandbox;
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
const webex = new MockWebex({
|
|
21
|
+
children: {
|
|
22
|
+
meetings: Meetings
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
sandbox = sinon.createSandbox();
|
|
27
|
+
|
|
28
|
+
url1 = `https://example.com/${uuid.v4()}`;
|
|
29
|
+
|
|
30
|
+
membersRequest = new MembersRequest({}, {
|
|
31
|
+
parent: webex
|
|
32
|
+
});
|
|
33
|
+
membersRequest.request = sinon.mock().returns(Promise.resolve({}));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
afterEach(() => {
|
|
37
|
+
sandbox.restore();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
describe('members request library', () => {
|
|
42
|
+
describe('#sendDialPadKey', () => {
|
|
43
|
+
it('sends a POST to the sendDtmf locus endpoint', async () => {
|
|
44
|
+
const locusUrl = url1;
|
|
45
|
+
const url = 'https://fakedeviceurl.com';
|
|
46
|
+
const tones = '1';
|
|
47
|
+
const memberId = 'test1';
|
|
48
|
+
|
|
49
|
+
await membersRequest.sendDialPadKey({
|
|
50
|
+
url,
|
|
51
|
+
tones,
|
|
52
|
+
memberId,
|
|
53
|
+
locusUrl
|
|
54
|
+
});
|
|
55
|
+
const requestParams = membersRequest.request.getCall(0).args[0];
|
|
56
|
+
|
|
57
|
+
assert.equal(requestParams.method, 'POST');
|
|
58
|
+
assert.equal(requestParams.uri, `${locusUrl}/participant/${memberId}/sendDtmf`);
|
|
59
|
+
assert.equal(requestParams.body.dtmf.tones, tones);
|
|
60
|
+
assert.equal(requestParams.body.device.url, url);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('#addMembers', () => {
|
|
65
|
+
it('sends a PUT to the locus endpoint', async () => {
|
|
66
|
+
const options = {
|
|
67
|
+
invitee: {
|
|
68
|
+
phoneNumber: '+18578675309'
|
|
69
|
+
},
|
|
70
|
+
locusUrl: url1
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
await membersRequest.addMembers(options);
|
|
74
|
+
const requestParams = membersRequest.request.getCall(0).args[0];
|
|
75
|
+
|
|
76
|
+
assert.equal(requestParams.method, 'PUT');
|
|
77
|
+
assert.equal(requestParams.uri, url1);
|
|
78
|
+
assert.equal(requestParams.body.invitees[0].address, '+18578675309');
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('#cancelPhoneInvite', () => {
|
|
83
|
+
it('sends a PUT to the locus endpoint', async () => {
|
|
84
|
+
const options = {
|
|
85
|
+
invitee: {
|
|
86
|
+
phoneNumber: '+18578675309'
|
|
87
|
+
},
|
|
88
|
+
locusUrl: url1
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
await membersRequest.cancelPhoneInvite(options);
|
|
92
|
+
const requestParams = membersRequest.request.getCall(0).args[0];
|
|
93
|
+
|
|
94
|
+
assert.equal(requestParams.method, 'PUT');
|
|
95
|
+
assert.equal(requestParams.uri, url1);
|
|
96
|
+
assert.equal(requestParams.body.invitees[0].address, '+18578675309');
|
|
97
|
+
assert.equal(requestParams.body.actionType, 'REMOVE');
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
});
|