@webex/plugin-meetings 3.0.0 → 3.1.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.
Files changed (138) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/config.d.ts +1 -0
  4. package/dist/config.js +2 -1
  5. package/dist/config.js.map +1 -1
  6. package/dist/constants.d.ts +5 -4
  7. package/dist/constants.js +8 -4
  8. package/dist/constants.js.map +1 -1
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.js +6 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/interpretation/index.js +16 -2
  13. package/dist/interpretation/index.js.map +1 -1
  14. package/dist/interpretation/siLanguage.js +1 -1
  15. package/dist/locus-info/mediaSharesUtils.js +15 -1
  16. package/dist/locus-info/mediaSharesUtils.js.map +1 -1
  17. package/dist/locus-info/selfUtils.js +5 -0
  18. package/dist/locus-info/selfUtils.js.map +1 -1
  19. package/dist/media/MediaConnectionAwaiter.d.ts +61 -0
  20. package/dist/media/MediaConnectionAwaiter.js +163 -0
  21. package/dist/media/MediaConnectionAwaiter.js.map +1 -0
  22. package/dist/media/index.js +4 -1
  23. package/dist/media/index.js.map +1 -1
  24. package/dist/media/properties.js +4 -24
  25. package/dist/media/properties.js.map +1 -1
  26. package/dist/meeting/index.d.ts +26 -7
  27. package/dist/meeting/index.js +893 -677
  28. package/dist/meeting/index.js.map +1 -1
  29. package/dist/meeting/muteState.d.ts +2 -8
  30. package/dist/meeting/muteState.js +37 -25
  31. package/dist/meeting/muteState.js.map +1 -1
  32. package/dist/meeting/request.d.ts +3 -0
  33. package/dist/meeting/request.js +32 -23
  34. package/dist/meeting/request.js.map +1 -1
  35. package/dist/meeting/util.js +1 -0
  36. package/dist/meeting/util.js.map +1 -1
  37. package/dist/meeting-info/utilv2.js +4 -1
  38. package/dist/meeting-info/utilv2.js.map +1 -1
  39. package/dist/meetings/index.d.ts +8 -0
  40. package/dist/meetings/index.js +20 -0
  41. package/dist/meetings/index.js.map +1 -1
  42. package/dist/multistream/mediaRequestManager.d.ts +2 -1
  43. package/dist/multistream/mediaRequestManager.js +1 -1
  44. package/dist/multistream/mediaRequestManager.js.map +1 -1
  45. package/dist/multistream/remoteMediaGroup.d.ts +2 -0
  46. package/dist/multistream/remoteMediaGroup.js +16 -2
  47. package/dist/multistream/remoteMediaGroup.js.map +1 -1
  48. package/dist/multistream/remoteMediaManager.d.ts +15 -0
  49. package/dist/multistream/remoteMediaManager.js +179 -65
  50. package/dist/multistream/remoteMediaManager.js.map +1 -1
  51. package/dist/multistream/sendSlotManager.d.ts +9 -1
  52. package/dist/multistream/sendSlotManager.js +22 -0
  53. package/dist/multistream/sendSlotManager.js.map +1 -1
  54. package/dist/reachability/clusterReachability.d.ts +1 -0
  55. package/dist/reachability/clusterReachability.js +29 -15
  56. package/dist/reachability/clusterReachability.js.map +1 -1
  57. package/dist/reachability/index.d.ts +4 -0
  58. package/dist/reachability/index.js +18 -2
  59. package/dist/reachability/index.js.map +1 -1
  60. package/dist/reachability/request.js +12 -10
  61. package/dist/reachability/request.js.map +1 -1
  62. package/dist/reachability/util.d.ts +7 -0
  63. package/dist/reachability/util.js +19 -0
  64. package/dist/reachability/util.js.map +1 -1
  65. package/dist/reconnection-manager/index.js +2 -1
  66. package/dist/reconnection-manager/index.js.map +1 -1
  67. package/dist/roap/index.d.ts +10 -2
  68. package/dist/roap/index.js +15 -0
  69. package/dist/roap/index.js.map +1 -1
  70. package/dist/roap/request.js +3 -3
  71. package/dist/roap/request.js.map +1 -1
  72. package/dist/roap/turnDiscovery.d.ts +64 -17
  73. package/dist/roap/turnDiscovery.js +307 -126
  74. package/dist/roap/turnDiscovery.js.map +1 -1
  75. package/dist/statsAnalyzer/index.js +53 -30
  76. package/dist/statsAnalyzer/index.js.map +1 -1
  77. package/dist/webinar/index.js +1 -1
  78. package/package.json +22 -22
  79. package/src/config.ts +1 -0
  80. package/src/constants.ts +7 -3
  81. package/src/index.ts +1 -0
  82. package/src/interpretation/index.ts +18 -1
  83. package/src/locus-info/mediaSharesUtils.ts +16 -0
  84. package/src/locus-info/selfUtils.ts +5 -0
  85. package/src/media/MediaConnectionAwaiter.ts +174 -0
  86. package/src/media/index.ts +3 -1
  87. package/src/media/properties.ts +6 -31
  88. package/src/meeting/index.ts +321 -106
  89. package/src/meeting/muteState.ts +34 -20
  90. package/src/meeting/request.ts +18 -2
  91. package/src/meeting/util.ts +1 -0
  92. package/src/meeting-info/utilv2.ts +2 -1
  93. package/src/meetings/index.ts +18 -0
  94. package/src/multistream/mediaRequestManager.ts +4 -1
  95. package/src/multistream/remoteMediaGroup.ts +19 -0
  96. package/src/multistream/remoteMediaManager.ts +101 -16
  97. package/src/multistream/sendSlotManager.ts +28 -0
  98. package/src/reachability/clusterReachability.ts +20 -5
  99. package/src/reachability/index.ts +24 -1
  100. package/src/reachability/request.ts +15 -11
  101. package/src/reachability/util.ts +21 -0
  102. package/src/reconnection-manager/index.ts +1 -1
  103. package/src/roap/index.ts +25 -3
  104. package/src/roap/request.ts +3 -3
  105. package/src/roap/turnDiscovery.ts +244 -78
  106. package/src/statsAnalyzer/index.ts +63 -27
  107. package/test/integration/spec/journey.js +14 -14
  108. package/test/integration/spec/space-meeting.js +1 -1
  109. package/test/unit/spec/interpretation/index.ts +39 -3
  110. package/test/unit/spec/locus-info/index.js +28 -19
  111. package/test/unit/spec/locus-info/mediaSharesUtils.ts +9 -0
  112. package/test/unit/spec/locus-info/selfUtils.js +42 -12
  113. package/test/unit/spec/media/MediaConnectionAwaiter.ts +344 -0
  114. package/test/unit/spec/media/index.ts +89 -78
  115. package/test/unit/spec/media/properties.ts +16 -70
  116. package/test/unit/spec/meeting/index.js +638 -139
  117. package/test/unit/spec/meeting/muteState.js +219 -67
  118. package/test/unit/spec/meeting/request.js +21 -0
  119. package/test/unit/spec/meeting/utils.js +6 -1
  120. package/test/unit/spec/meeting-info/utilv2.js +6 -0
  121. package/test/unit/spec/meetings/index.js +40 -20
  122. package/test/unit/spec/multistream/mediaRequestManager.ts +20 -2
  123. package/test/unit/spec/multistream/remoteMediaGroup.ts +79 -1
  124. package/test/unit/spec/multistream/remoteMediaManager.ts +199 -1
  125. package/test/unit/spec/multistream/sendSlotManager.ts +50 -18
  126. package/test/unit/spec/reachability/clusterReachability.ts +86 -22
  127. package/test/unit/spec/reachability/index.ts +197 -60
  128. package/test/unit/spec/reachability/request.js +15 -7
  129. package/test/unit/spec/reachability/util.ts +32 -2
  130. package/test/unit/spec/reconnection-manager/index.js +28 -0
  131. package/test/unit/spec/roap/index.ts +61 -6
  132. package/test/unit/spec/roap/turnDiscovery.ts +298 -16
  133. package/test/unit/spec/stats-analyzer/index.js +179 -0
  134. package/dist/member/member.types.d.ts +0 -11
  135. package/dist/member/member.types.js +0 -17
  136. package/dist/member/member.types.js.map +0 -1
  137. package/src/member/member.types.ts +0 -13
  138. /package/test/unit/spec/locus-info/{lib/selfConstant.js → selfConstant.js} +0 -0
@@ -15,21 +15,25 @@ describe('plugin-meetings', () => {
15
15
 
16
16
  const fakeLocus = {info: 'this is a fake locus'};
17
17
 
18
- const createFakeLocalStream = (id, muted) => {
18
+ const createFakeLocalStream = (id, userMuted, systemMuted) => {
19
19
  return {
20
20
  id,
21
21
  setServerMuted: sinon.stub(),
22
22
  setUnmuteAllowed: sinon.stub(),
23
- setMuted: sinon.stub(),
24
- muted,
23
+ setUserMuted: sinon.stub(),
24
+ userMuted,
25
+ systemMuted,
26
+ get muted() {
27
+ return this.userMuted || this.systemMuted;
28
+ },
25
29
  };
26
30
  };
27
31
 
28
32
  beforeEach(async () => {
29
33
  meeting = {
30
34
  mediaProperties: {
31
- audioStream: createFakeLocalStream('fake audio stream', false),
32
- videoStream: createFakeLocalStream('fake video stream', false),
35
+ audioStream: createFakeLocalStream('fake audio stream', false, false),
36
+ videoStream: createFakeLocalStream('fake video stream', false, false),
33
37
  },
34
38
  remoteMuted: false,
35
39
  unmuteAllowed: true,
@@ -109,9 +113,9 @@ describe('plugin-meetings', () => {
109
113
  assert.isTrue(audio.isRemotelyMuted());
110
114
  });
111
115
 
112
- it('does local unmute if localAudioUnmuteRequired is received', async () => {
113
- // first we need to mute have the local stream muted
114
- meeting.mediaProperties.audioStream.muted = true;
116
+ it('does local audio unmute if localAudioUnmuteRequired is received', async () => {
117
+ // first we need to have the local stream user muted
118
+ meeting.mediaProperties.audioStream.userMuted = true;
115
119
  audio.handleLocalStreamChange(meeting);
116
120
 
117
121
  assert.isTrue(audio.isMuted());
@@ -119,8 +123,12 @@ describe('plugin-meetings', () => {
119
123
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
120
124
 
121
125
  // now simulate server requiring us to locally unmute
126
+ // assuming setServerMuted succeeds at updating userMuted
127
+ meeting.mediaProperties.audioStream.setServerMuted = sinon.stub().callsFake((muted) => {
128
+ meeting.mediaProperties.audioStream.userMuted = muted;
129
+ });
122
130
  audio.handleServerLocalUnmuteRequired(meeting);
123
-
131
+
124
132
  await testUtils.flushPromises();
125
133
 
126
134
  // check that local stream was unmuted
@@ -137,9 +145,41 @@ describe('plugin-meetings', () => {
137
145
  assert.isFalse(audio.isMuted());
138
146
  });
139
147
 
148
+ it('handles localAudioUnmuteRequired but does not send unmute to server if system is muted', async () => {
149
+ // first we need to have the local stream user muted and system muted
150
+ meeting.mediaProperties.audioStream.userMuted = true;
151
+ meeting.mediaProperties.audioStream.systemMuted = true;
152
+ audio.handleLocalStreamChange(meeting);
153
+
154
+ assert.isTrue(audio.isMuted());
155
+
156
+ MeetingUtil.remoteUpdateAudioVideo.resetHistory();
157
+
158
+ // now simulate server requiring us to locally unmute
159
+ // assuming setServerMuted succeeds at updating userMuted
160
+ meeting.mediaProperties.audioStream.setServerMuted = sinon.stub().callsFake((muted) => {
161
+ meeting.mediaProperties.audioStream.userMuted = muted;
162
+ });
163
+ audio.handleServerLocalUnmuteRequired(meeting);
164
+
165
+ await testUtils.flushPromises();
166
+
167
+ // check that local stream was unmuted
168
+ assert.calledWith(
169
+ meeting.mediaProperties.audioStream.setServerMuted,
170
+ false,
171
+ 'localUnmuteRequired'
172
+ );
173
+
174
+ // system was muted so local unmute was not sent to server
175
+ assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
176
+
177
+ assert.isTrue(audio.isMuted());
178
+ });
179
+
140
180
  it('does local video unmute if localVideoUnmuteRequired is received', async () => {
141
- // first we need to mute
142
- meeting.mediaProperties.videoStream.muted = true;
181
+ // first we need to have the local stream user muted
182
+ meeting.mediaProperties.videoStream.userMuted = true;
143
183
  video.handleLocalStreamChange(meeting);
144
184
 
145
185
  assert.isTrue(video.isMuted());
@@ -147,7 +187,12 @@ describe('plugin-meetings', () => {
147
187
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
148
188
 
149
189
  // now simulate server requiring us to locally unmute
190
+ // assuming setServerMuted succeeds at updating userMuted
191
+ meeting.mediaProperties.videoStream.setServerMuted = sinon.stub().callsFake((muted) => {
192
+ meeting.mediaProperties.videoStream.userMuted = muted;
193
+ });
150
194
  video.handleServerLocalUnmuteRequired(meeting);
195
+
151
196
  await testUtils.flushPromises();
152
197
 
153
198
  // check that local stream was unmuted
@@ -164,11 +209,43 @@ describe('plugin-meetings', () => {
164
209
  assert.isFalse(video.isMuted());
165
210
  });
166
211
 
212
+ it('handles localVideoUnmuteRequired but does not send unmute to server if system is muted', async () => {
213
+ // first we need to have the local stream user muted and system muted
214
+ meeting.mediaProperties.videoStream.userMuted = true;
215
+ meeting.mediaProperties.videoStream.systemMuted = true;
216
+ audio.handleLocalStreamChange(meeting);
217
+
218
+ assert.isTrue(video.isMuted());
219
+
220
+ MeetingUtil.remoteUpdateAudioVideo.resetHistory();
221
+
222
+ // now simulate server requiring us to locally unmute
223
+ // assuming setServerMuted succeeds at updating userMuted
224
+ meeting.mediaProperties.videoStream.setServerMuted = sinon.stub().callsFake((muted) => {
225
+ meeting.mediaProperties.videoStream.userMuted = muted;
226
+ });
227
+ video.handleServerLocalUnmuteRequired(meeting);
228
+
229
+ await testUtils.flushPromises();
230
+
231
+ // check that local stream was unmuted
232
+ assert.calledWith(
233
+ meeting.mediaProperties.videoStream.setServerMuted,
234
+ false,
235
+ 'localUnmuteRequired'
236
+ );
237
+
238
+ // system was muted so local unmute was not sent to server
239
+ assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
240
+
241
+ assert.isTrue(video.isMuted());
242
+ });
243
+
167
244
  describe('#isLocallyMuted()', () => {
168
245
  it('does not consider remote mute status for audio', async () => {
169
246
  // simulate being already remote muted and locally unmuted
170
247
  meeting.remoteMuted = true;
171
- meeting.mediaProperties.audioStream.muted = false;
248
+ meeting.mediaProperties.audioStream.userMuted = false;
172
249
 
173
250
  // create a new MuteState instance
174
251
  audio = createMuteState(AUDIO, meeting, true);
@@ -182,7 +259,7 @@ describe('plugin-meetings', () => {
182
259
  it('does not consider remote mute status for video', async () => {
183
260
  // simulate being already remote muted
184
261
  meeting.remoteVideoMuted = true;
185
- meeting.mediaProperties.videoStream.muted = false;
262
+ meeting.mediaProperties.videoStream.userMuted = false;
186
263
 
187
264
  // create a new MuteState instance
188
265
  video = createMuteState(VIDEO, meeting, true);
@@ -202,27 +279,44 @@ describe('plugin-meetings', () => {
202
279
  await testUtils.flushPromises();
203
280
  });
204
281
 
205
- const simulateAudioMuteChange = async (muteValue) => {
206
- meeting.mediaProperties.audioStream.muted = muteValue;
207
- audio.handleLocalStreamMuteStateChange(meeting, muteValue);
282
+ const simulateAudioUserMuteChange = async (muteValue) => {
283
+ meeting.mediaProperties.audioStream.userMuted = muteValue;
284
+ audio.handleLocalStreamMuteStateChange(meeting);
285
+
286
+ await testUtils.flushPromises();
287
+ };
288
+
289
+ const simulateAudioSystemMuteChange = async (muteValue) => {
290
+ meeting.mediaProperties.audioStream.systemMuted = muteValue;
291
+ audio.handleLocalStreamMuteStateChange(meeting);
208
292
 
209
293
  await testUtils.flushPromises();
210
294
  };
211
295
 
212
- const simulateVideoMuteChange = async (muteValue) => {
213
- meeting.mediaProperties.videoStream.muted = muteValue;
214
- video.handleLocalStreamMuteStateChange(meeting, muteValue);
296
+ const simulateVideoUserMuteChange = async (muteValue) => {
297
+ meeting.mediaProperties.videoStream.userMuted = muteValue;
298
+ video.handleLocalStreamMuteStateChange(meeting);
215
299
 
216
300
  await testUtils.flushPromises();
217
301
  };
218
302
 
219
- it('returns correct value in isMuted() methods after local stream is muted/unmuted', async () => {
303
+ it('returns correct value in isMuted() methods after local stream is user muted/unmuted', async () => {
220
304
  // mute
221
- await simulateAudioMuteChange(true);
305
+ await simulateAudioUserMuteChange(true);
222
306
  assert.isTrue(audio.isMuted());
223
307
 
224
308
  // unmute
225
- await simulateAudioMuteChange(false);
309
+ await simulateAudioUserMuteChange(false);
310
+ assert.isFalse(audio.isMuted());
311
+ });
312
+
313
+ it('returns correct value in isMuted() methods after local stream is system muted/unmuted', async () => {
314
+ // mute
315
+ await simulateAudioSystemMuteChange(true);
316
+ assert.isTrue(audio.isMuted());
317
+
318
+ // unmute
319
+ await simulateAudioSystemMuteChange(false);
226
320
  assert.isFalse(audio.isMuted());
227
321
  });
228
322
 
@@ -231,7 +325,7 @@ describe('plugin-meetings', () => {
231
325
  audio.handleServerRemoteMuteUpdate(meeting, true, true);
232
326
 
233
327
  // unmute
234
- await simulateAudioMuteChange(false);
328
+ await simulateAudioUserMuteChange(false);
235
329
 
236
330
  // check that remote unmute was sent to server
237
331
  assert.calledOnce(meeting.members.muteMember);
@@ -245,7 +339,7 @@ describe('plugin-meetings', () => {
245
339
  video.handleServerRemoteMuteUpdate(meeting, true, true);
246
340
 
247
341
  // unmute
248
- await simulateVideoMuteChange(false);
342
+ await simulateVideoUserMuteChange(false);
249
343
 
250
344
  // check that remote unmute was sent to server
251
345
  assert.calledOnce(meeting.members.muteMember);
@@ -259,7 +353,7 @@ describe('plugin-meetings', () => {
259
353
  video.handleServerRemoteMuteUpdate(meeting, false, true);
260
354
 
261
355
  // unmute
262
- await simulateVideoMuteChange(false);
356
+ await simulateVideoUserMuteChange(false);
263
357
 
264
358
  // check that remote unmute was not sent to server
265
359
  assert.notCalled(meeting.members.muteMember);
@@ -270,7 +364,7 @@ describe('plugin-meetings', () => {
270
364
  it('calls setServerMuted with "clientRequestFailed" when server request for local mute fails', async () => {
271
365
  MeetingUtil.remoteUpdateAudioVideo = sinon.stub().rejects(new Error('fake error'));
272
366
 
273
- await simulateAudioMuteChange(true);
367
+ await simulateAudioUserMuteChange(true);
274
368
 
275
369
  assert.calledOnceWithExactly(
276
370
  meeting.mediaProperties.audioStream.setServerMuted,
@@ -289,7 +383,7 @@ describe('plugin-meetings', () => {
289
383
  meeting.members.muteMember = sinon.stub().rejects();
290
384
  meeting.mediaProperties.audioStream.setServerMuted.resetHistory();
291
385
 
292
- await simulateAudioMuteChange(false);
386
+ await simulateAudioUserMuteChange(false);
293
387
 
294
388
  assert.calledOnceWithExactly(
295
389
  meeting.mediaProperties.audioStream.setServerMuted,
@@ -313,11 +407,11 @@ describe('plugin-meetings', () => {
313
407
 
314
408
  // the stream is initially unmuted
315
409
  // simulate many mute changes with the last one matching the first one
316
- await simulateAudioMuteChange(true);
317
- await simulateAudioMuteChange(false);
318
- await simulateAudioMuteChange(true);
319
- await simulateAudioMuteChange(false);
320
- await simulateAudioMuteChange(true);
410
+ await simulateAudioUserMuteChange(true);
411
+ await simulateAudioUserMuteChange(false);
412
+ await simulateAudioUserMuteChange(true);
413
+ await simulateAudioUserMuteChange(false);
414
+ await simulateAudioUserMuteChange(true);
321
415
 
322
416
  // so far there should have been only 1 request to server (because our stub hasn't resolved yet
323
417
  // and MuteState sends only 1 server request at a time)
@@ -342,8 +436,8 @@ describe('plugin-meetings', () => {
342
436
  );
343
437
 
344
438
  // 2 client requests, one after another without waiting for first one to resolve
345
- await simulateAudioMuteChange(true);
346
- await simulateAudioMuteChange(false);
439
+ await simulateAudioUserMuteChange(true);
440
+ await simulateAudioUserMuteChange(false);
347
441
 
348
442
  assert.calledOnce(MeetingUtil.remoteUpdateAudioVideo);
349
443
  assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, true, undefined);
@@ -364,7 +458,7 @@ describe('plugin-meetings', () => {
364
458
 
365
459
  it('does not send remote mute for video', async () => {
366
460
  // mute
367
- await simulateVideoMuteChange(true);
461
+ await simulateVideoUserMuteChange(true);
368
462
 
369
463
  assert.isTrue(video.isMuted());
370
464
 
@@ -376,7 +470,7 @@ describe('plugin-meetings', () => {
376
470
  meeting.members.muteMember.resetHistory();
377
471
 
378
472
  // unmute
379
- await simulateVideoMuteChange(false);
473
+ await simulateVideoUserMuteChange(false);
380
474
 
381
475
  assert.isFalse(video.isMuted());
382
476
 
@@ -390,22 +484,22 @@ describe('plugin-meetings', () => {
390
484
  meeting.video = video;
391
485
 
392
486
  // mute audio -> the call to remoteUpdateAudioVideo should have video undefined
393
- await simulateAudioMuteChange(true);
487
+ await simulateAudioUserMuteChange(true);
394
488
  assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, true, undefined);
395
489
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
396
490
 
397
491
  // now mute video -> the call to remoteUpdateAudioVideo should have unmute for video and undefined for audio
398
- await simulateVideoMuteChange(true);
492
+ await simulateVideoUserMuteChange(true);
399
493
  assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, undefined, true);
400
494
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
401
495
 
402
496
  // now unmute the audio -> the call to remoteUpdateAudioVideo should have video undefined
403
- await simulateAudioMuteChange(false);
497
+ await simulateAudioUserMuteChange(false);
404
498
  assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, false, undefined);
405
499
  MeetingUtil.remoteUpdateAudioVideo.resetHistory();
406
500
 
407
501
  // unmute video -> the call to remoteUpdateAudioVideo should have audio undefined
408
- await simulateVideoMuteChange(false);
502
+ await simulateVideoUserMuteChange(false);
409
503
  assert.calledWith(MeetingUtil.remoteUpdateAudioVideo, meeting, undefined, false);
410
504
  });
411
505
  });
@@ -414,12 +508,13 @@ describe('plugin-meetings', () => {
414
508
  let meeting;
415
509
  let muteState;
416
510
  let setServerMutedSpy;
417
- let setMutedSpy, setUnmuteAllowedSpy;
511
+ let setUserMutedSpy, setUnmuteAllowedSpy;
418
512
 
419
513
  const setupMeeting = (
420
514
  mediaType,
421
515
  remoteMuted = false,
422
- muted = false,
516
+ userMuted = false,
517
+ systemMuted = false,
423
518
  defineStreams = true
424
519
  ) => {
425
520
  const remoteMuteField = mediaType === AUDIO ? 'remoteMuted' : 'remoteVideoMuted';
@@ -427,10 +522,10 @@ describe('plugin-meetings', () => {
427
522
  meeting = {
428
523
  mediaProperties: {
429
524
  audioStream: defineStreams
430
- ? createFakeLocalStream('fake audio stream', muted)
525
+ ? createFakeLocalStream('fake audio stream', userMuted, systemMuted)
431
526
  : undefined,
432
527
  videoStream: defineStreams
433
- ? createFakeLocalStream('fake video stream', muted)
528
+ ? createFakeLocalStream('fake video stream', userMuted, systemMuted)
434
529
  : undefined,
435
530
  },
436
531
  [remoteMuteField]: remoteMuted,
@@ -447,8 +542,14 @@ describe('plugin-meetings', () => {
447
542
  };
448
543
  };
449
544
 
450
- const setup = async (mediaType, remoteMuted = false, muted = false, defineStreams = true) => {
451
- setupMeeting(mediaType, remoteMuted, muted, defineStreams);
545
+ const setup = async (
546
+ mediaType,
547
+ remoteMuted = false,
548
+ userMuted = false,
549
+ systemMuted = false,
550
+ defineStreams = true
551
+ ) => {
552
+ setupMeeting(mediaType, remoteMuted, userMuted, systemMuted, defineStreams);
452
553
 
453
554
  muteState = createMuteState(mediaType, meeting, true);
454
555
  muteState.handleLocalStreamChange(meeting);
@@ -467,10 +568,10 @@ describe('plugin-meetings', () => {
467
568
  mediaType === AUDIO
468
569
  ? meeting.mediaProperties.audioStream?.setServerMuted
469
570
  : meeting.mediaProperties.videoStream?.setServerMuted;
470
- setMutedSpy =
571
+ setUserMutedSpy =
471
572
  mediaType === AUDIO
472
- ? meeting.mediaProperties.audioStream?.setMuted
473
- : meeting.mediaProperties.videoStream?.setMuted;
573
+ ? meeting.mediaProperties.audioStream?.setUserMuted
574
+ : meeting.mediaProperties.videoStream?.setUserMuted;
474
575
 
475
576
  clearSpies();
476
577
  };
@@ -478,8 +579,25 @@ describe('plugin-meetings', () => {
478
579
  const clearSpies = () => {
479
580
  setUnmuteAllowedSpy?.resetHistory();
480
581
  setServerMutedSpy?.resetHistory();
481
- setMutedSpy?.resetHistory();
582
+ setUserMutedSpy?.resetHistory();
482
583
  };
584
+
585
+ const simulateUserMute = (mediaType, mute) => {
586
+ if (mediaType === AUDIO) {
587
+ meeting.mediaProperties.audioStream.userMuted = mute;
588
+ } else {
589
+ meeting.mediaProperties.videoStream.userMuted = mute;
590
+ }
591
+ };
592
+
593
+ const simulateSystemMute = (mediaType, mute) => {
594
+ if (mediaType === AUDIO) {
595
+ meeting.mediaProperties.audioStream.systemMuted = mute;
596
+ } else {
597
+ meeting.mediaProperties.videoStream.systemMuted = mute;
598
+ }
599
+ };
600
+
483
601
  const tests = [
484
602
  {mediaType: AUDIO, title: 'audio'},
485
603
  {mediaType: VIDEO, title: 'video'},
@@ -513,16 +631,17 @@ describe('plugin-meetings', () => {
513
631
  const setupWithoutInit = async (
514
632
  mediaType,
515
633
  remoteMuted = false,
516
- muted = false,
634
+ userMuted = false,
635
+ systemMuted = false,
517
636
  defineStreams = true
518
637
  ) => {
519
- setupMeeting(mediaType, remoteMuted, muted, defineStreams);
638
+ setupMeeting(mediaType, remoteMuted, userMuted, systemMuted, defineStreams);
520
639
 
521
640
  muteState = new MuteState(mediaType, meeting, true);
522
641
  };
523
642
 
524
643
  it('nothing goes bad when stream is undefined', async () => {
525
- await setupWithoutInit(mediaType, false, false, false);
644
+ await setupWithoutInit(mediaType, false, false, false, false);
526
645
  setupSpies(mediaType);
527
646
 
528
647
  muteState.init(meeting);
@@ -530,8 +649,20 @@ describe('plugin-meetings', () => {
530
649
  assert.isTrue(muteState.state.client.localMute);
531
650
  });
532
651
 
533
- it('tests when stream muted is true and remoteMuted is false', async () => {
534
- await setupWithoutInit(mediaType, false, true);
652
+ it('tests when stream user muted is true and remoteMuted is false', async () => {
653
+ await setupWithoutInit(mediaType, false, true, false, true);
654
+ setupSpies(mediaType);
655
+
656
+ muteState.init(meeting);
657
+
658
+ assert.calledWith(setUnmuteAllowedSpy, muteState.state.server.unmuteAllowed);
659
+ assert.notCalled(setServerMutedSpy);
660
+ assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
661
+ assert.isTrue(muteState.state.client.localMute);
662
+ });
663
+
664
+ it('tests when stream system muted is true and remoteMuted is false', async () => {
665
+ await setupWithoutInit(mediaType, false, false, true, true);
535
666
  setupSpies(mediaType);
536
667
 
537
668
  muteState.init(meeting);
@@ -542,8 +673,8 @@ describe('plugin-meetings', () => {
542
673
  assert.isTrue(muteState.state.client.localMute);
543
674
  });
544
675
 
545
- it('tests when stream muted is false and remoteMuted is false', async () => {
546
- await setupWithoutInit(mediaType, false, false);
676
+ it('tests when both stream user muted and system muted are false and remoteMuted is false', async () => {
677
+ await setupWithoutInit(mediaType, false, false, false, true);
547
678
  setupSpies(mediaType);
548
679
 
549
680
  muteState.init(meeting);
@@ -556,7 +687,7 @@ describe('plugin-meetings', () => {
556
687
 
557
688
  it('tests when remoteMuted is true', async () => {
558
689
  // testing that muteLocalStream is called
559
- await setupWithoutInit(mediaType, true);
690
+ await setupWithoutInit(mediaType, true, false, false, true);
560
691
  setupSpies(mediaType);
561
692
 
562
693
  muteState.init(meeting);
@@ -568,27 +699,48 @@ describe('plugin-meetings', () => {
568
699
 
569
700
  describe('#handleLocalStreamMuteStateChange', () => {
570
701
  it('checks when ignoreMuteStateChange is true nothing changes', async () => {
571
- await setup(mediaType, false, false);
702
+ await setup(mediaType, false, false, false, true);
572
703
  muteState.ignoreMuteStateChange = true;
573
704
 
574
- muteState.handleLocalStreamMuteStateChange(meeting, true);
705
+ simulateUserMute(mediaType, true);
706
+ muteState.handleLocalStreamMuteStateChange(meeting);
575
707
  assert.notCalled(MeetingUtil.remoteUpdateAudioVideo);
576
708
 
577
709
  assert.isFalse(muteState.state.client.localMute);
578
710
  });
579
711
 
580
- it('tests localMute - true to false', async () => {
581
- await setup(mediaType, false, true);
712
+ it('tests localMute - user mute from true to false', async () => {
713
+ await setup(mediaType, false, true, false, true);
714
+
715
+ simulateUserMute(mediaType, false);
716
+ muteState.handleLocalStreamMuteStateChange(meeting);
717
+ assert.equal(muteState.state.client.localMute, false);
718
+ assert.called(MeetingUtil.remoteUpdateAudioVideo);
719
+ });
720
+
721
+ it('tests localMute - user mute from false to true', async () => {
722
+ await setup(mediaType, false, false, false, true);
723
+
724
+ simulateUserMute(mediaType, true);
725
+ muteState.handleLocalStreamMuteStateChange(meeting);
726
+ assert.equal(muteState.state.client.localMute, true);
727
+ assert.called(MeetingUtil.remoteUpdateAudioVideo);
728
+ });
729
+
730
+ it('tests localMute - system mute from true to false', async () => {
731
+ await setup(mediaType, false, false, true, true);
582
732
 
583
- muteState.handleLocalStreamMuteStateChange(meeting, false);
733
+ simulateSystemMute(mediaType, false);
734
+ muteState.handleLocalStreamMuteStateChange(meeting);
584
735
  assert.equal(muteState.state.client.localMute, false);
585
736
  assert.called(MeetingUtil.remoteUpdateAudioVideo);
586
737
  });
587
738
 
588
- it('tests localMute - false to true', async () => {
589
- await setup(mediaType, false, false);
739
+ it('tests localMute - system mute from false to true', async () => {
740
+ await setup(mediaType, false, false, false, true);
590
741
 
591
- muteState.handleLocalStreamMuteStateChange(meeting, true);
742
+ simulateSystemMute(mediaType, true);
743
+ muteState.handleLocalStreamMuteStateChange(meeting);
592
744
  assert.equal(muteState.state.client.localMute, true);
593
745
  assert.called(MeetingUtil.remoteUpdateAudioVideo);
594
746
  });
@@ -609,7 +761,7 @@ describe('plugin-meetings', () => {
609
761
  muteState.state.client.localMute,
610
762
  'somereason'
611
763
  );
612
- assert.notCalled(setMutedSpy);
764
+ assert.notCalled(setUserMutedSpy);
613
765
  });
614
766
 
615
767
  it('nothing explodes when streams are undefined', async () => {
@@ -194,12 +194,14 @@ describe('plugin-meetings', () => {
194
194
  const roapMessage = 'roap-message';
195
195
  const permissionToken = 'permission-token';
196
196
  const installationId = 'installationId';
197
+ const reachability = 'reachability';
197
198
 
198
199
  await meetingsRequest.joinMeeting({
199
200
  locusUrl,
200
201
  deviceUrl,
201
202
  correlationId,
202
203
  roapMessage,
204
+ reachability,
203
205
  permissionToken,
204
206
  });
205
207
  const requestParams = meetingsRequest.request.getCall(0).args[0];
@@ -212,6 +214,9 @@ describe('plugin-meetings', () => {
212
214
  assert.equal(requestParams.body.permissionToken, 'permission-token');
213
215
  assert.equal(requestParams.body.device.regionCode, 'WEST-COAST');
214
216
  assert.include(requestParams.body.device.localIp, '127.0.0');
217
+ assert.deepEqual(requestParams.body.localMedias, [
218
+ {localSdp: '{"roapMessage":"roap-message","reachability":"reachability"}'},
219
+ ]);
215
220
 
216
221
  assert.calledOnceWithExactly(anonymizeIpSpy, '127.0.0.1');
217
222
  });
@@ -365,6 +370,22 @@ describe('plugin-meetings', () => {
365
370
  assert.deepEqual(requestParams.body.locale, undefined);
366
371
  });
367
372
 
373
+ it('adds alias to request when they are provided', async () => {
374
+ await meetingsRequest.joinMeeting({
375
+ alias: 'assigned name',
376
+ });
377
+ const requestParams = meetingsRequest.request.getCall(0).args[0];
378
+
379
+ assert.deepEqual(requestParams.body.alias, 'assigned name');
380
+ });
381
+
382
+ it('does not add alias to request when they are not provided', async () => {
383
+ await meetingsRequest.joinMeeting({});
384
+ const requestParams = meetingsRequest.request.getCall(0).args[0];
385
+
386
+ assert.deepEqual(requestParams.body.alias, undefined);
387
+ });
388
+
368
389
  it('includes joinCookie and ipver correctly', async () => {
369
390
  const locusUrl = 'locusURL';
370
391
  const deviceUrl = 'deviceUrl';
@@ -402,13 +402,18 @@ describe('plugin-meetings', () => {
402
402
  };
403
403
 
404
404
  const parseLocusJoinSpy = sinon.stub(MeetingUtil, 'parseLocusJoin');
405
- await MeetingUtil.joinMeeting(meeting, {});
405
+ await MeetingUtil.joinMeeting(meeting, {
406
+ reachability: 'reachability',
407
+ roapMessage: 'roapMessage',
408
+ });
406
409
 
407
410
  assert.calledOnce(meeting.meetingRequest.joinMeeting);
408
411
  const parameter = meeting.meetingRequest.joinMeeting.getCall(0).args[0];
409
412
 
410
413
  assert.equal(parameter.inviteeAddress, 'meetingJoinUrl');
411
414
  assert.equal(parameter.preferTranscoding, true);
415
+ assert.equal(parameter.reachability, 'reachability');
416
+ assert.equal(parameter.roapMessage, 'roapMessage');
412
417
 
413
418
  assert.calledWith(webex.internal.newMetrics.submitClientEvent, {
414
419
  name: 'client.locus.join.request',
@@ -252,6 +252,12 @@ describe('plugin-meetings', () => {
252
252
  it('SIP meeting address from excepted domain', () => {
253
253
  assert.equal(MeetingInfoUtil.getWebexSite('10019857020@meet.webex.com'), null);
254
254
  });
255
+ it('SIP meeting address from excepted domain for IC', () => {
256
+ assert.equal(MeetingInfoUtil.getWebexSite('10019857020@meet-intb.ciscospark.com'), null);
257
+ });
258
+ it('SIP meeting address from webex domain', () => {
259
+ assert.equal(MeetingInfoUtil.getWebexSite('10019857020@webex.com'), null);
260
+ });
255
261
  it('invalid domain', () => {
256
262
  assert.equal(MeetingInfoUtil.getWebexSite('invaliddomain'), null);
257
263
  });