@webex/plugin-meetings 1.149.1 → 1.151.0
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/constants.js +14 -4
- package/dist/constants.js.map +1 -1
- package/dist/locus-info/mediaSharesUtils.js +88 -11
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/meeting/index.js +368 -42
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/request.js +17 -41
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting-info/index.js +1 -1
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/util.js +14 -0
- package/dist/meeting-info/util.js.map +1 -1
- package/dist/meetings/index.js +1 -1
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/util.js +0 -16
- package/dist/meetings/util.js.map +1 -1
- package/dist/members/index.js +72 -11
- package/dist/members/index.js.map +1 -1
- package/dist/metrics/config.js +6 -0
- package/dist/metrics/config.js.map +1 -1
- package/dist/metrics/index.js +26 -1
- package/dist/metrics/index.js.map +1 -1
- package/dist/peer-connection-manager/index.js +1 -1
- package/dist/peer-connection-manager/index.js.map +1 -1
- package/package.json +5 -5
- package/src/constants.js +11 -2
- package/src/locus-info/mediaSharesUtils.js +84 -12
- package/src/meeting/index.js +350 -29
- package/src/meeting/request.js +50 -29
- package/src/meeting-info/index.js +4 -1
- package/src/meeting-info/util.js +13 -0
- package/src/meetings/index.js +1 -1
- package/src/meetings/util.js +0 -14
- package/src/members/index.js +80 -11
- package/src/metrics/config.js +6 -0
- package/src/metrics/index.js +23 -2
- package/src/peer-connection-manager/index.js +7 -2
- package/test/integration/spec/journey.js +177 -3
- package/test/integration/spec/space-meeting.js +33 -5
- package/test/unit/spec/meeting/index.js +547 -2
- package/test/utils/testUtils.js +18 -1
- package/test/utils/webex-test-users.js +2 -0
package/src/meetings/util.js
CHANGED
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
CORRELATION_ID,
|
|
9
9
|
EVENT_TRIGGERS
|
|
10
10
|
} from '../constants';
|
|
11
|
-
import ParameterError from '../common/errors/parameter';
|
|
12
11
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
13
12
|
import Trigger from '../common/events/trigger-proxy';
|
|
14
13
|
|
|
@@ -32,19 +31,6 @@ import Trigger from '../common/events/trigger-proxy';
|
|
|
32
31
|
|
|
33
32
|
const MeetingsUtil = {};
|
|
34
33
|
|
|
35
|
-
MeetingsUtil.extractDestination = (destination, type) => {
|
|
36
|
-
let dest = destination;
|
|
37
|
-
|
|
38
|
-
if (type === _LOCUS_ID_) {
|
|
39
|
-
if (!(destination && destination.url)) {
|
|
40
|
-
throw new ParameterError('You cannot create a meeting by locus without a locus.url defined');
|
|
41
|
-
}
|
|
42
|
-
dest = destination.url;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return dest;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
34
|
MeetingsUtil.getMeetingAddedType = (type) => (type === _LOCUS_ID_ ? _INCOMING_ : _CREATED_);
|
|
49
35
|
|
|
50
36
|
MeetingsUtil.handleRoapMercury = (envelope, meetingCollection) => {
|
package/src/members/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import {isEmpty} from 'lodash';
|
|
5
5
|
import {StatelessWebexPlugin} from '@webex/webex-core';
|
|
6
6
|
|
|
7
|
-
import {MEETINGS, EVENT_TRIGGERS, FLOOR_ACTION, CONTENT} from '../constants';
|
|
7
|
+
import {MEETINGS, EVENT_TRIGGERS, FLOOR_ACTION, CONTENT, WHITEBOARD} from '../constants';
|
|
8
8
|
import Trigger from '../common/events/trigger-proxy';
|
|
9
9
|
import Member from '../member';
|
|
10
10
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
@@ -132,6 +132,14 @@ export default class Members extends StatelessWebexPlugin {
|
|
|
132
132
|
* @memberof Members
|
|
133
133
|
*/
|
|
134
134
|
this.mediaShareContentId = null;
|
|
135
|
+
/**
|
|
136
|
+
* The current mediaShareWhiteboardId for the meeting
|
|
137
|
+
* @instance
|
|
138
|
+
* @type {String}
|
|
139
|
+
* @private
|
|
140
|
+
* @memberof Members
|
|
141
|
+
*/
|
|
142
|
+
this.mediaShareWhiteboardId = null;
|
|
135
143
|
/**
|
|
136
144
|
* The current recordingId for the meeting, if it exists
|
|
137
145
|
* @instance
|
|
@@ -281,20 +289,49 @@ export default class Members extends StatelessWebexPlugin {
|
|
|
281
289
|
* @memberof Members
|
|
282
290
|
*/
|
|
283
291
|
locusMediaSharesUpdate(payload) {
|
|
284
|
-
const currentContent = payload.current;
|
|
285
|
-
const previousContent = payload.previous;
|
|
292
|
+
const currentContent = payload.current?.content;
|
|
293
|
+
const previousContent = payload.previous?.content;
|
|
294
|
+
const currentWhiteboard = payload.current?.whiteboard;
|
|
295
|
+
const previousWhiteboard = payload.previous?.whiteboard;
|
|
286
296
|
let whoSharing = null;
|
|
287
297
|
let whoStopped = null;
|
|
288
298
|
|
|
289
|
-
if (currentContent
|
|
299
|
+
if (currentContent?.beneficiaryId) {
|
|
290
300
|
if (currentContent.disposition === FLOOR_ACTION.GRANTED) {
|
|
291
|
-
whoSharing = currentContent.
|
|
292
|
-
|
|
301
|
+
whoSharing = currentContent.beneficiaryId;
|
|
302
|
+
this.mediaShareWhiteboardId = null;
|
|
303
|
+
this.mediaShareContentId = whoSharing;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (previousContent?.disposition === FLOOR_ACTION.GRANTED) {
|
|
307
|
+
if (currentContent.disposition === FLOOR_ACTION.RELEASED) {
|
|
308
|
+
whoStopped = currentContent.beneficiaryId;
|
|
309
|
+
this.mediaShareContentId = null;
|
|
310
|
+
}
|
|
311
|
+
else if (currentContent.disposition === FLOOR_ACTION.GRANTED && currentContent.beneficiaryId !== previousContent.beneficiaryId) {
|
|
312
|
+
whoStopped = previousContent.beneficiaryId;
|
|
313
|
+
}
|
|
293
314
|
}
|
|
294
|
-
|
|
295
|
-
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (currentWhiteboard?.beneficiaryId) {
|
|
318
|
+
if (currentWhiteboard.disposition === FLOOR_ACTION.GRANTED) {
|
|
319
|
+
whoSharing = currentWhiteboard.beneficiaryId;
|
|
320
|
+
this.mediaShareContentId = null;
|
|
321
|
+
this.mediaShareWhiteboardId = whoSharing;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (previousWhiteboard?.disposition === FLOOR_ACTION.GRANTED) {
|
|
325
|
+
if (currentWhiteboard.disposition === FLOOR_ACTION.RELEASED) {
|
|
326
|
+
whoStopped = currentWhiteboard.beneficiaryId;
|
|
327
|
+
this.mediaShareWhiteboardId = null;
|
|
328
|
+
}
|
|
329
|
+
else if (currentWhiteboard.disposition === FLOOR_ACTION.GRANTED && currentWhiteboard.beneficiaryId !== previousWhiteboard.beneficiaryId) {
|
|
330
|
+
whoStopped = previousWhiteboard.beneficiaryId;
|
|
331
|
+
}
|
|
296
332
|
}
|
|
297
333
|
}
|
|
334
|
+
|
|
298
335
|
if (whoSharing) {
|
|
299
336
|
const shareMember = this.membersCollection.get(whoSharing);
|
|
300
337
|
|
|
@@ -309,7 +346,7 @@ export default class Members extends StatelessWebexPlugin {
|
|
|
309
346
|
stopMember.setIsContentSharing(false);
|
|
310
347
|
}
|
|
311
348
|
}
|
|
312
|
-
|
|
349
|
+
|
|
313
350
|
Trigger.trigger(
|
|
314
351
|
this,
|
|
315
352
|
{
|
|
@@ -318,8 +355,8 @@ export default class Members extends StatelessWebexPlugin {
|
|
|
318
355
|
},
|
|
319
356
|
EVENT_TRIGGERS.MEMBERS_CONTENT_UPDATE,
|
|
320
357
|
{
|
|
321
|
-
|
|
322
|
-
|
|
358
|
+
activeSharingId: whoSharing,
|
|
359
|
+
endedSharingId: whoStopped
|
|
323
360
|
}
|
|
324
361
|
);
|
|
325
362
|
}
|
|
@@ -524,6 +561,36 @@ export default class Members extends StatelessWebexPlugin {
|
|
|
524
561
|
}
|
|
525
562
|
}
|
|
526
563
|
|
|
564
|
+
/**
|
|
565
|
+
* Update the media share whiteboard id
|
|
566
|
+
* @param {Object} locus
|
|
567
|
+
* @param {String} [whiteboardId] optional, takes precedence
|
|
568
|
+
* @throws {Error}
|
|
569
|
+
* @returns {undefined}
|
|
570
|
+
* @memberof Members
|
|
571
|
+
*/
|
|
572
|
+
setMediaShareWhiteboardId(locus, whiteboardId) {
|
|
573
|
+
if (whiteboardId) {
|
|
574
|
+
this.mediaShareWhiteboardId = whiteboardId;
|
|
575
|
+
}
|
|
576
|
+
else if (locus) {
|
|
577
|
+
const whiteboardMediaShare =
|
|
578
|
+
locus.mediaShares &&
|
|
579
|
+
locus.mediaShares.length &&
|
|
580
|
+
locus.mediaShares.find((mediaShare) => mediaShare.name === WHITEBOARD);
|
|
581
|
+
|
|
582
|
+
this.mediaShareWhiteboardId =
|
|
583
|
+
(whiteboardMediaShare &&
|
|
584
|
+
whiteboardMediaShare.floor &&
|
|
585
|
+
whiteboardMediaShare.floor.beneficiary &&
|
|
586
|
+
whiteboardMediaShare.floor.beneficiary.id) ||
|
|
587
|
+
null;
|
|
588
|
+
}
|
|
589
|
+
else {
|
|
590
|
+
throw new ParameterError('Setting hostid for the Members module should be done with a locus object or hostId');
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
527
594
|
/**
|
|
528
595
|
* Find all the updates, and added members
|
|
529
596
|
* Removed/left members will end up in updates
|
|
@@ -552,6 +619,7 @@ export default class Members extends StatelessWebexPlugin {
|
|
|
552
619
|
selfId: this.selfId,
|
|
553
620
|
hostId: this.hostId,
|
|
554
621
|
contentSharingId: this.mediaShareContentId,
|
|
622
|
+
whiteboardSharingId: this.mediaShareWhiteboardId,
|
|
555
623
|
type: this.type
|
|
556
624
|
})
|
|
557
625
|
);
|
|
@@ -563,6 +631,7 @@ export default class Members extends StatelessWebexPlugin {
|
|
|
563
631
|
selfId: this.selfId,
|
|
564
632
|
hostId: this.hostId,
|
|
565
633
|
contentSharingId: this.mediaShareContentId,
|
|
634
|
+
whiteboardSharingId: this.mediaShareWhiteboardId,
|
|
566
635
|
type: this.type
|
|
567
636
|
})
|
|
568
637
|
);
|
package/src/metrics/config.js
CHANGED
|
@@ -126,6 +126,12 @@ export const eventType = {
|
|
|
126
126
|
// Fired when the client changes its local UI/layout to a content sharing view,
|
|
127
127
|
// because it is expecting to display share media.
|
|
128
128
|
SHARE_LAYOUT_DISPLAYED: 'client.share.layout.displayed',
|
|
129
|
+
// Fired when the user of the client starts a whiteboard share (e.g. click 'Share Live' button).
|
|
130
|
+
WHITEBOARD_SHARE_INITIATED: 'client.whiteboard.share.initiated',
|
|
131
|
+
// Fired when the meeting floor is released for whiteboard share
|
|
132
|
+
WHITEBOARD_SHARE_STOPPED: 'client.whiteboard.share.stopped',
|
|
133
|
+
// When the client receives a successful response from locus indicating that it has the floor for whiteboard sharing.
|
|
134
|
+
WHITEBOARD_SHARE_FLOOR_GRANTED: 'client.whiteboard.share.floor-granted',
|
|
129
135
|
MUTED: 'client.muted',
|
|
130
136
|
UNMUTED: 'client.unmuted',
|
|
131
137
|
LEAVE: 'client.call.leave',
|
package/src/metrics/index.js
CHANGED
|
@@ -48,7 +48,15 @@ const getLocalNetworkPrefix = (localIp) => {
|
|
|
48
48
|
|
|
49
49
|
const triggerTimers = ({event, meeting, data}) => {
|
|
50
50
|
switch (event) {
|
|
51
|
+
case eventType.CALL_INITIATED:
|
|
52
|
+
meeting.setStartCallInitiateJoinReq();
|
|
53
|
+
break;
|
|
54
|
+
case eventType.LOCUS_JOIN_REQUEST:
|
|
55
|
+
meeting.setEndCallInitiateJoinReq();
|
|
56
|
+
meeting.setStartJoinReqResp();
|
|
57
|
+
break;
|
|
51
58
|
case eventType.LOCUS_JOIN_RESPONSE:
|
|
59
|
+
meeting.setEndJoinReqResp();
|
|
52
60
|
meeting.setStartSetupDelay(mediaType.AUDIO);
|
|
53
61
|
meeting.setStartSetupDelay(mediaType.VIDEO);
|
|
54
62
|
meeting.setStartSendingMediaDelay(mediaType.AUDIO);
|
|
@@ -60,6 +68,12 @@ const triggerTimers = ({event, meeting, data}) => {
|
|
|
60
68
|
case eventType.SENDING_MEDIA_START:
|
|
61
69
|
meeting.setEndSendingMediaDelay(data.mediaType);
|
|
62
70
|
break;
|
|
71
|
+
case eventType.LOCAL_SDP_GENERATED:
|
|
72
|
+
meeting.setStartLocalSDPGenRemoteSDPRecvDelay();
|
|
73
|
+
break;
|
|
74
|
+
case eventType.REMOTE_SDP_RECEIVED:
|
|
75
|
+
meeting.setEndLocalSDPGenRemoteSDPRecvDelay();
|
|
76
|
+
break;
|
|
63
77
|
default:
|
|
64
78
|
break;
|
|
65
79
|
}
|
|
@@ -144,6 +158,7 @@ class Metrics {
|
|
|
144
158
|
|
|
145
159
|
if (!meeting && meetingId) {
|
|
146
160
|
meeting = this.meetingCollection.get(meetingId);
|
|
161
|
+
options.meeting = meeting;
|
|
147
162
|
}
|
|
148
163
|
|
|
149
164
|
if (meeting) {
|
|
@@ -228,6 +243,9 @@ class Metrics {
|
|
|
228
243
|
if (options.recoveredBy) {
|
|
229
244
|
payload.event.recoveredBy = options.recoveredBy;
|
|
230
245
|
}
|
|
246
|
+
if (options.joinTimes) {
|
|
247
|
+
payload.event.joinTimes = options.joinTimes;
|
|
248
|
+
}
|
|
231
249
|
}
|
|
232
250
|
|
|
233
251
|
return payload;
|
|
@@ -259,7 +277,7 @@ class Metrics {
|
|
|
259
277
|
* @memberof Metrics
|
|
260
278
|
*/
|
|
261
279
|
initMediaPayload(eventType, identifiers, options = {}) {
|
|
262
|
-
const {audioSetupDelay, videoSetupDelay} = options;
|
|
280
|
+
const {audioSetupDelay, videoSetupDelay, joinTimes} = options;
|
|
263
281
|
|
|
264
282
|
const payload = {
|
|
265
283
|
eventId: uuid.v4(),
|
|
@@ -290,7 +308,10 @@ class Metrics {
|
|
|
290
308
|
canProceed: true,
|
|
291
309
|
identifiers,
|
|
292
310
|
intervals: [options.intervalData],
|
|
293
|
-
|
|
311
|
+
joinTimes,
|
|
312
|
+
eventData: {
|
|
313
|
+
webClientDomain: window.location.hostname
|
|
314
|
+
},
|
|
294
315
|
sourceMetadata: {
|
|
295
316
|
applicationSoftwareType: CLIENT_NAME,
|
|
296
317
|
applicationSoftwareVersion: this.webex.version,
|
|
@@ -288,7 +288,12 @@ pc.addStream = (peerConnection, stream) => {
|
|
|
288
288
|
* @param {String} meetingId
|
|
289
289
|
* @returns {undefined}
|
|
290
290
|
*/
|
|
291
|
-
pc.setRemoteSessionDetails = (
|
|
291
|
+
pc.setRemoteSessionDetails = (
|
|
292
|
+
peerConnection,
|
|
293
|
+
typeStr,
|
|
294
|
+
remoteSdp,
|
|
295
|
+
meetingId,
|
|
296
|
+
) => {
|
|
292
297
|
LoggerProxy.logger.log(`PeerConnectionManager:index#setRemoteSessionDetails --> Setting the remote description type: ${typeStr}State: ${peerConnection.signalingState}`);
|
|
293
298
|
const sdp = remoteSdp;
|
|
294
299
|
|
|
@@ -314,7 +319,7 @@ pc.setRemoteSessionDetails = (peerConnection, typeStr, remoteSdp, meetingId) =>
|
|
|
314
319
|
})
|
|
315
320
|
)
|
|
316
321
|
.then(() => {
|
|
317
|
-
if (
|
|
322
|
+
if (peerConnection.signalingState === SDP.STABLE) {
|
|
318
323
|
Metrics.postEvent({
|
|
319
324
|
event: eventType.REMOTE_SDP_RECEIVED,
|
|
320
325
|
meetingId
|
|
@@ -13,7 +13,7 @@ const webexTestUsers = require('../../utils/webex-test-users');
|
|
|
13
13
|
|
|
14
14
|
const {isBrowser} = BrowserDetection();
|
|
15
15
|
|
|
16
|
-
let userSet, alice, bob, chris, enumerateSpy;
|
|
16
|
+
let userSet, alice, bob, chris, enumerateSpy, channelUrlA, channelUrlB;
|
|
17
17
|
|
|
18
18
|
skipInNode(describe)('plugin-meetings', () => {
|
|
19
19
|
describe('journey', () => {
|
|
@@ -32,6 +32,8 @@ skipInNode(describe)('plugin-meetings', () => {
|
|
|
32
32
|
alice.webex.meetings.name = 'alice';
|
|
33
33
|
bob.webex.meetings.name = 'bob';
|
|
34
34
|
chris.webex.meetings.name = 'chris';
|
|
35
|
+
channelUrlA = 'https://board-a.wbx2.com/board/api/v1/channels/49cfb550-5517-11eb-a2af-1b9e4bc3da13';
|
|
36
|
+
channelUrlB = 'https://board-a.wbx2.com/board/api/v1/channels/977a7330-54f4-11eb-b1ef-91f5eefc7bf3';
|
|
35
37
|
})
|
|
36
38
|
.then(() => Promise.all([testUtils.syncAndEndMeeting(alice),
|
|
37
39
|
testUtils.syncAndEndMeeting(bob)]))
|
|
@@ -162,6 +164,41 @@ skipInNode(describe)('plugin-meetings', () => {
|
|
|
162
164
|
}));
|
|
163
165
|
});
|
|
164
166
|
|
|
167
|
+
// Enabled when config.enableUnifiedMeetings = true
|
|
168
|
+
xdescribe('Conversation URL', () => {
|
|
169
|
+
describe('Successful 1:1 meeting', () => {
|
|
170
|
+
it('Fetch meeting information with a conversation URL for a 1:1 space', async () => {
|
|
171
|
+
assert.equal(Object.keys(bob.webex.meetings.getAllMeetings()), 0);
|
|
172
|
+
assert.equal(Object.keys(chris.webex.meetings.getAllMeetings()), 0);
|
|
173
|
+
|
|
174
|
+
const conversation = await chris.webex.internal.conversation.create({participants: [bob]});
|
|
175
|
+
|
|
176
|
+
await chris.webex.internal.conversation.post(conversation, {displayName: 'hello world how are you '});
|
|
177
|
+
|
|
178
|
+
await Promise.all([
|
|
179
|
+
testUtils.delayedPromise(chris.webex.meetings.create(conversation.url, 'CONVERSATION_URL')),
|
|
180
|
+
testUtils.waitForEvents([{scope: chris.webex.meetings, event: 'meeting:added', user: chris}])
|
|
181
|
+
])
|
|
182
|
+
.then(function chrisJoinsMeeting() {
|
|
183
|
+
return Promise.all([
|
|
184
|
+
testUtils.delayedPromise(chris.meeting.join()),
|
|
185
|
+
testUtils.waitForEvents([{scope: bob.webex.meetings, event: 'meeting:added', user: bob},
|
|
186
|
+
{scope: chris.meeting, event: 'meeting:stateChange', user: chris}])
|
|
187
|
+
.then((response) => {
|
|
188
|
+
assert.equal(response[0].result.payload.currentState, 'ACTIVE');
|
|
189
|
+
})
|
|
190
|
+
]);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('Fetch meeting information with invalid conversation URL and throws error', () => {
|
|
195
|
+
chris.webex.meetings.meetingInfo.fetchMeetingInfo('http://some-invalid.com', 'CONVERSATION_URL').then((response) => {
|
|
196
|
+
assert(response.result === '404');
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
|
|
165
202
|
describe('Successful 1:1 meeting (including Guest)', function () {
|
|
166
203
|
before(() => {
|
|
167
204
|
// Workaround since getDisplayMedia requires a user gesture to be activated, and this is a integration tests
|
|
@@ -484,7 +521,7 @@ skipInNode(describe)('plugin-meetings', () => {
|
|
|
484
521
|
}),
|
|
485
522
|
testUtils.waitForEvents([{scope: bob.meeting.members, event: 'members:update'}])
|
|
486
523
|
.then((response) => {
|
|
487
|
-
console.log('SCREEN SHARE RESPONSE ', JSON.stringify(response));
|
|
524
|
+
console.log('SCREEN SHARE RESPONSE ', JSON.stringify(response, testUtils.getCircularReplacer()));
|
|
488
525
|
}),
|
|
489
526
|
testUtils.waitForEvents([{scope: alice.meeting, event: 'media:ready'}])
|
|
490
527
|
.then((response) => {
|
|
@@ -515,7 +552,7 @@ skipInNode(describe)('plugin-meetings', () => {
|
|
|
515
552
|
}),
|
|
516
553
|
testUtils.waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
|
|
517
554
|
.then((response) => {
|
|
518
|
-
console.log('SCREEN SHARE RESPONSE ', JSON.stringify(response));
|
|
555
|
+
console.log('SCREEN SHARE RESPONSE ', JSON.stringify(response, testUtils.getCircularReplacer()));
|
|
519
556
|
}),
|
|
520
557
|
testUtils.waitForEvents([{scope: bob.meeting, event: 'media:ready'}])
|
|
521
558
|
.then((response) => {
|
|
@@ -553,6 +590,143 @@ skipInNode(describe)('plugin-meetings', () => {
|
|
|
553
590
|
assert.equal(alice.meeting.shareStatus, 'no_share');
|
|
554
591
|
}));
|
|
555
592
|
|
|
593
|
+
it('alice shares whiteboard A', () => Promise.all([
|
|
594
|
+
testUtils.delayedPromise(alice.meeting.startWhiteboardShare(channelUrlA)),
|
|
595
|
+
testUtils.waitForEvents([
|
|
596
|
+
{scope: alice.meeting, event: 'meeting:startedSharingWhiteboard'}
|
|
597
|
+
]),
|
|
598
|
+
testUtils.waitForEvents([{scope: bob.meeting, event: 'meeting:startedSharingWhiteboard'}])
|
|
599
|
+
.then((response) => {
|
|
600
|
+
const {memberId, resourceUrl} = response[0].result;
|
|
601
|
+
|
|
602
|
+
assert.equal(memberId, alice.meeting.selfId);
|
|
603
|
+
assert.equal(resourceUrl, channelUrlA);
|
|
604
|
+
}),
|
|
605
|
+
testUtils.waitForEvents([{scope: bob.meeting.members, event: 'members:update'}])
|
|
606
|
+
.then((response) => {
|
|
607
|
+
console.log('WHITEBOARD SHARE RESPONSE ', JSON.stringify(response, testUtils.getCircularReplacer()));
|
|
608
|
+
})
|
|
609
|
+
])
|
|
610
|
+
.then(() => {
|
|
611
|
+
assert.equal(alice.meeting.isSharing, false);
|
|
612
|
+
assert.equal(alice.meeting.shareStatus, 'whiteboard_share_active');
|
|
613
|
+
assert.equal(bob.meeting.shareStatus, 'whiteboard_share_active');
|
|
614
|
+
}));
|
|
615
|
+
|
|
616
|
+
it('bob steals share from alice with whiteboard B', () => Promise.all([
|
|
617
|
+
testUtils.delayedPromise(bob.meeting.startWhiteboardShare(channelUrlB)),
|
|
618
|
+
testUtils.waitForEvents([
|
|
619
|
+
{scope: bob.meeting, event: 'meeting:startedSharingWhiteboard'}
|
|
620
|
+
]),
|
|
621
|
+
testUtils.waitForEvents([{scope: alice.meeting, event: 'meeting:startedSharingWhiteboard'}])
|
|
622
|
+
.then((response) => {
|
|
623
|
+
const {memberId, resourceUrl} = response[0].result;
|
|
624
|
+
|
|
625
|
+
assert.equal(memberId, bob.meeting.selfId);
|
|
626
|
+
assert.equal(resourceUrl, channelUrlB);
|
|
627
|
+
}),
|
|
628
|
+
testUtils.waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
|
|
629
|
+
.then((response) => {
|
|
630
|
+
console.log('WHITEBOARD SHARE RESPONSE ', JSON.stringify(response, testUtils.getCircularReplacer()));
|
|
631
|
+
})
|
|
632
|
+
])
|
|
633
|
+
.then(() => {
|
|
634
|
+
assert.equal(bob.meeting.isSharing, false);
|
|
635
|
+
assert.equal(alice.meeting.shareStatus, 'whiteboard_share_active');
|
|
636
|
+
assert.equal(bob.meeting.shareStatus, 'whiteboard_share_active');
|
|
637
|
+
}));
|
|
638
|
+
|
|
639
|
+
it('bob stops sharing ', () => Promise.all([
|
|
640
|
+
// Wait for peerConnection to stabalize
|
|
641
|
+
testUtils.waitUntil(20000),
|
|
642
|
+
testUtils.delayedPromise(bob.meeting.stopWhiteboardShare(channelUrlB)),
|
|
643
|
+
testUtils.waitForEvents([{scope: bob.meeting, event: 'meeting:stoppedSharingWhiteboard'}]),
|
|
644
|
+
testUtils.waitForEvents([{scope: alice.meeting, event: 'meeting:stoppedSharingWhiteboard'}])
|
|
645
|
+
])
|
|
646
|
+
.then(() => {
|
|
647
|
+
assert.equal(bob.meeting.isSharing, false);
|
|
648
|
+
assert.equal(bob.meeting.shareStatus, 'no_share');
|
|
649
|
+
assert.equal(alice.meeting.shareStatus, 'no_share');
|
|
650
|
+
}));
|
|
651
|
+
|
|
652
|
+
it('alice shares whiteboard B', () => Promise.all([
|
|
653
|
+
testUtils.delayedPromise(alice.meeting.startWhiteboardShare(channelUrlB)),
|
|
654
|
+
testUtils.waitForEvents([
|
|
655
|
+
{scope: alice.meeting, event: 'meeting:startedSharingWhiteboard'}
|
|
656
|
+
]),
|
|
657
|
+
testUtils.waitForEvents([{scope: bob.meeting, event: 'meeting:startedSharingWhiteboard'}])
|
|
658
|
+
.then((response) => {
|
|
659
|
+
const {memberId, resourceUrl} = response[0].result;
|
|
660
|
+
|
|
661
|
+
assert.equal(memberId, alice.meeting.selfId);
|
|
662
|
+
assert.equal(resourceUrl, channelUrlB);
|
|
663
|
+
}),
|
|
664
|
+
testUtils.waitForEvents([{scope: bob.meeting.members, event: 'members:update'}])
|
|
665
|
+
.then((response) => {
|
|
666
|
+
console.log('WHITEBOARD SHARE RESPONSE ', JSON.stringify(response, testUtils.getCircularReplacer()));
|
|
667
|
+
})
|
|
668
|
+
])
|
|
669
|
+
.then(() => {
|
|
670
|
+
assert.equal(alice.meeting.isSharing, false);
|
|
671
|
+
assert.equal(alice.meeting.shareStatus, 'whiteboard_share_active');
|
|
672
|
+
assert.equal(bob.meeting.shareStatus, 'whiteboard_share_active');
|
|
673
|
+
}));
|
|
674
|
+
|
|
675
|
+
it('bob steals the share from alice with desktop share', () => Promise.all([
|
|
676
|
+
testUtils.delayedPromise(bob.meeting.shareScreen()),
|
|
677
|
+
testUtils.waitForEvents([{scope: alice.meeting, event: 'meeting:stoppedSharingWhiteboard'}]),
|
|
678
|
+
testUtils.waitForEvents([{scope: bob.meeting, event: 'meeting:startedSharingLocal'}]),
|
|
679
|
+
testUtils.waitForEvents([{scope: alice.meeting, event: 'meeting:startedSharingRemote'}])
|
|
680
|
+
.then((response) => {
|
|
681
|
+
assert.equal(response[0].result.memberId, bob.meeting.selfId);
|
|
682
|
+
}),
|
|
683
|
+
testUtils.waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
|
|
684
|
+
.then((response) => {
|
|
685
|
+
console.log('SCREEN SHARE RESPONSE ', JSON.stringify(response, testUtils.getCircularReplacer()));
|
|
686
|
+
}),
|
|
687
|
+
testUtils.waitForEvents([{scope: bob.meeting, event: 'media:ready'}])
|
|
688
|
+
.then((response) => {
|
|
689
|
+
console.log('MEDIA:READY event ', response[0].result);
|
|
690
|
+
assert.equal(response[0].result.type === 'localShare', true);
|
|
691
|
+
})
|
|
692
|
+
])
|
|
693
|
+
.then(() => {
|
|
694
|
+
const heightResolution = DEFAULT_RESOLUTIONS.meetings.screenResolution.idealHeight;
|
|
695
|
+
|
|
696
|
+
// TODO: Re-eanable Safari when screensharing issues have been resolved
|
|
697
|
+
if (!isBrowser('safari')) {
|
|
698
|
+
assert.equal(bob.meeting.mediaProperties.shareTrack.getConstraints().height, heightResolution);
|
|
699
|
+
}
|
|
700
|
+
assert.equal(bob.meeting.isSharing, true);
|
|
701
|
+
assert.equal(bob.meeting.shareStatus, 'local_share_active');
|
|
702
|
+
assert.equal(alice.meeting.shareStatus, 'remote_share_active');
|
|
703
|
+
|
|
704
|
+
return testUtils.waitUntil(10000);
|
|
705
|
+
}));
|
|
706
|
+
|
|
707
|
+
it('bob shares whiteboard B', () => Promise.all([
|
|
708
|
+
testUtils.delayedPromise(bob.meeting.startWhiteboardShare(channelUrlB)),
|
|
709
|
+
testUtils.waitForEvents([
|
|
710
|
+
{scope: bob.meeting, event: 'meeting:startedSharingWhiteboard'}
|
|
711
|
+
]),
|
|
712
|
+
testUtils.waitForEvents([{scope: alice.meeting, event: 'meeting:startedSharingWhiteboard'}])
|
|
713
|
+
.then((response) => {
|
|
714
|
+
const {memberId, resourceUrl} = response[0].result;
|
|
715
|
+
|
|
716
|
+
assert.equal(memberId, bob.meeting.selfId);
|
|
717
|
+
assert.equal(resourceUrl, channelUrlB);
|
|
718
|
+
}),
|
|
719
|
+
testUtils.waitForEvents([{scope: alice.meeting.members, event: 'members:update'}])
|
|
720
|
+
.then((response) => {
|
|
721
|
+
console.log('WHITEBOARD SHARE RESPONSE ', JSON.stringify(response, testUtils.getCircularReplacer()));
|
|
722
|
+
})
|
|
723
|
+
])
|
|
724
|
+
.then(() => {
|
|
725
|
+
assert.equal(bob.meeting.isSharing, false);
|
|
726
|
+
assert.equal(alice.meeting.shareStatus, 'whiteboard_share_active');
|
|
727
|
+
assert.equal(bob.meeting.shareStatus, 'whiteboard_share_active');
|
|
728
|
+
}));
|
|
729
|
+
|
|
556
730
|
it('alice adds chris as guest to 1:1 meeting', () => Promise.all([
|
|
557
731
|
testUtils.delayedPromise(alice.meeting.invite({emailAddress: chris.emailAddress})),
|
|
558
732
|
testUtils.waitForEvents([{scope: chris.webex.meetings, event: 'meeting:added', user: chris}]),
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
import {assert} from '@webex/test-helper-chai';
|
|
3
3
|
import {skipInNode, jenkinsOnly} from '@webex/test-helper-mocha';
|
|
4
|
+
import {patterns} from '@webex/common';
|
|
5
|
+
import MeetingInfoUtil from '@webex/plugin-meetings/src/meeting-info/utilv2';
|
|
4
6
|
|
|
5
7
|
import CMR from '../../utils/cmr';
|
|
6
8
|
import testUtils from '../../utils/testUtils';
|
|
@@ -44,6 +46,15 @@ skipInNode(describe)('plugin-meetings', () => {
|
|
|
44
46
|
console.log('CONVERSATION', conversation);
|
|
45
47
|
space = conversation;
|
|
46
48
|
})
|
|
49
|
+
.then(async () => {
|
|
50
|
+
const destinationWithType = await alice.webex.meetings.meetingInfo.fetchMeetingInfo(space.url, 'CONVERSATION_URL');
|
|
51
|
+
const destinationNoType = await alice.webex.meetings.meetingInfo.fetchMeetingInfo(space.url);
|
|
52
|
+
|
|
53
|
+
assert.exists(destinationNoType);
|
|
54
|
+
assert.exists(destinationWithType);
|
|
55
|
+
assert.exists(destinationNoType.body.meetingNumber);
|
|
56
|
+
assert.exists(destinationWithType.body.meetingNumber);
|
|
57
|
+
})
|
|
47
58
|
.then(function aliceStartsMeeting() {
|
|
48
59
|
return Promise.all([
|
|
49
60
|
testUtils.delayedPromise(alice.webex.meetings.create(space.url)),
|
|
@@ -57,17 +68,34 @@ skipInNode(describe)('plugin-meetings', () => {
|
|
|
57
68
|
{scope: chris.webex.meetings, event: 'meeting:added', user: chris}])
|
|
58
69
|
])));
|
|
59
70
|
|
|
71
|
+
xit('Should fetch user info using user hydra id with the new api', () => alice.webex.rooms.create({title: 'sample'})
|
|
72
|
+
.then((room) => MeetingInfoUtil.getDestinationType({
|
|
73
|
+
destination: room.creatorId,
|
|
74
|
+
webex: alice.webex
|
|
75
|
+
}))
|
|
76
|
+
.then((destinationType) => MeetingInfoUtil.getRequestBody(destinationType))
|
|
77
|
+
.then((res) => {
|
|
78
|
+
assert.exists(res.sipUrl, 'sipURL didnt exist');
|
|
79
|
+
assert.match(res.sipUrl, patterns.email); // assert sipURL is email
|
|
80
|
+
}));
|
|
81
|
+
|
|
60
82
|
// Enable this test when we are going to enable the unified space meeeting .
|
|
61
83
|
// We cannot change the config on load as the meetingInfo function loads dynamically
|
|
62
|
-
xit('Should fetch meeting
|
|
63
|
-
alice.webex.meetings.config.experimental.enableUnifiedMeetings = true;
|
|
84
|
+
xit('Should fetch meeting info using space url with the new api', async () => {
|
|
64
85
|
const res = await alice.webex.meetings.meetingInfo.fetchMeetingInfo(space.url, 'CONVERSATION_URL');
|
|
65
86
|
|
|
66
|
-
assert.exists(res.meetingNumber);
|
|
87
|
+
assert.exists(res.body.meetingNumber);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
xit('Bob fetches meeting info with SIP URI before joining', async () => {
|
|
91
|
+
const {sipUri} = alice.meeting;
|
|
92
|
+
const res = await bob.webex.meetings.meetingInfo.fetchMeetingInfo(sipUri, 'SIP_URI');
|
|
93
|
+
const {meetingNumber} = res.body;
|
|
67
94
|
|
|
68
|
-
alice.
|
|
95
|
+
assert(meetingNumber === alice.meeting.meetingNumber, 'meetingNumber matches alice meeting number');
|
|
69
96
|
});
|
|
70
97
|
|
|
98
|
+
|
|
71
99
|
it('Bob and chris joins space meeting', () => testUtils.waitForStateChange(alice.meeting, 'JOINED')
|
|
72
100
|
.then(() => testUtils.waitForStateChange(bob.meeting, 'IDLE'))
|
|
73
101
|
.then(() => testUtils.waitForStateChange(chris.meeting, 'IDLE'))
|
|
@@ -97,7 +125,7 @@ skipInNode(describe)('plugin-meetings', () => {
|
|
|
97
125
|
|
|
98
126
|
|
|
99
127
|
it('alice adds x user as guest to space meeting', () => Promise.all([
|
|
100
|
-
testUtils.delayedPromise(guest.webex.meetings.create(alice.meeting.
|
|
128
|
+
testUtils.delayedPromise(guest.webex.meetings.create(alice.meeting.sipUri)),
|
|
101
129
|
testUtils.waitForEvents([{scope: guest.webex.meetings, event: 'meeting:added', user: guest}])
|
|
102
130
|
]).then(() =>
|
|
103
131
|
Promise.all([
|