@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.
@@ -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
- let sdp = remoteSdp;
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, {meetingId, remoteQualityLevel, enableRtx}) => {
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
- peerConnection.sdp = peerConnection.sdp.replace(/\na=extmap.*/g, '');
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
+ });