@webex/plugin-meetings 3.8.0-next.15 → 3.8.0-next.17

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.
@@ -23,11 +23,13 @@ import {
23
23
  ReachabilityResultsForBackend,
24
24
  TransportResultForBackend,
25
25
  GetClustersTrigger,
26
+ NatType,
26
27
  } from './reachability.types';
27
28
  import {
28
29
  ClientMediaIpsUpdatedEventData,
29
30
  ClusterReachability,
30
31
  Events,
32
+ NatTypeUpdatedEventData,
31
33
  ResultEventData,
32
34
  } from './clusterReachability';
33
35
  import EventsScope from '../common/events/events-scope';
@@ -64,6 +66,7 @@ export default class Reachability extends EventsScope {
64
66
  resultsCount = {videoMesh: {udp: 0}, public: {udp: 0, tcp: 0, xtls: 0}};
65
67
  startTime = undefined;
66
68
  totalDuration = undefined;
69
+ natType = NatType.Unknown;
67
70
 
68
71
  protected lastTrigger?: string;
69
72
 
@@ -309,6 +312,7 @@ export default class Reachability extends EventsScope {
309
312
  reachability_vmn_tcp_failed: 0,
310
313
  reachability_vmn_xtls_success: 0,
311
314
  reachability_vmn_xtls_failed: 0,
315
+ natType: this.natType,
312
316
  };
313
317
 
314
318
  const updateStats = (clusterType: 'public' | 'vmn', result: ClusterReachabilityResult) => {
@@ -967,6 +971,13 @@ export default class Reachability extends EventsScope {
967
971
  }
968
972
  );
969
973
 
974
+ this.clusterReachability[key].on(
975
+ Events.natTypeUpdated,
976
+ async (data: NatTypeUpdatedEventData) => {
977
+ this.natType = data.natType;
978
+ }
979
+ );
980
+
970
981
  this.clusterReachability[key].start(); // not awaiting on purpose
971
982
  });
972
983
  }
@@ -7,6 +7,11 @@ export type TransportResult = {
7
7
  clientMediaIPs?: string[];
8
8
  };
9
9
 
10
+ export enum NatType {
11
+ Unknown = 'unknown',
12
+ SymmetricNat = 'symmetric-nat',
13
+ }
14
+
10
15
  // reachability result for a specific media cluster
11
16
  export type ClusterReachabilityResult = {
12
17
  udp: TransportResult;
@@ -27,6 +32,7 @@ export type ReachabilityMetrics = {
27
32
  reachability_vmn_tcp_failed: number;
28
33
  reachability_vmn_xtls_success: number;
29
34
  reachability_vmn_xtls_failed: number;
35
+ natType: NatType;
30
36
  };
31
37
 
32
38
  /**
@@ -12682,6 +12682,31 @@ describe('plugin-meetings', () => {
12682
12682
  });
12683
12683
  });
12684
12684
  });
12685
+
12686
+ describe('handleShareVideoStreamMuteStateChange', () => {
12687
+ it('should emit MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE event with correct fields', () => {
12688
+ meeting.isMultistream = true;
12689
+ meeting.statsAnalyzer = {shareVideoEncoderImplementation: 'OpenH264'};
12690
+ meeting.mediaProperties.shareVideoStream = {
12691
+ getSettings: sinon.stub().returns({displaySurface: 'monitor', frameRate: 30}),
12692
+ };
12693
+
12694
+ meeting.handleShareVideoStreamMuteStateChange(true);
12695
+
12696
+ assert.calledOnceWithExactly(
12697
+ Metrics.sendBehavioralMetric,
12698
+ BEHAVIORAL_METRICS.MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE,
12699
+ {
12700
+ correlationId: meeting.correlationId,
12701
+ muted: true,
12702
+ encoderImplementation: 'OpenH264',
12703
+ displaySurface: 'monitor',
12704
+ isMultistream: true,
12705
+ frameRate: 30,
12706
+ }
12707
+ );
12708
+ });
12709
+ });
12685
12710
  });
12686
12711
 
12687
12712
  describe('#startKeepAlive', () => {
@@ -9,7 +9,9 @@ import {
9
9
  ResultEventData,
10
10
  Events,
11
11
  ClientMediaIpsUpdatedEventData,
12
+ NatTypeUpdatedEventData,
12
13
  } from '@webex/plugin-meetings/src/reachability/clusterReachability'; // replace with actual path
14
+ import { NatType } from 'packages/@webex/plugin-meetings/dist/reachability/reachability.types';
13
15
 
14
16
  describe('ClusterReachability', () => {
15
17
  let previousRTCPeerConnection;
@@ -17,15 +19,17 @@ describe('ClusterReachability', () => {
17
19
  let fakePeerConnection;
18
20
  let gatherIceCandidatesSpy;
19
21
 
20
- const emittedEvents: Record<Events, (ResultEventData | ClientMediaIpsUpdatedEventData)[]> = {
22
+ const emittedEvents: Record<Events, (ResultEventData | ClientMediaIpsUpdatedEventData | NatTypeUpdatedEventData)[]> = {
21
23
  [Events.resultReady]: [],
22
24
  [Events.clientMediaIpsUpdated]: [],
25
+ [Events.natTypeUpdated]: [],
23
26
  };
24
27
  const FAKE_OFFER = {type: 'offer', sdp: 'fake sdp'};
25
28
 
26
29
  const resetEmittedEvents = () => {
27
30
  emittedEvents[Events.resultReady].length = 0;
28
31
  emittedEvents[Events.clientMediaIpsUpdated].length = 0;
32
+ emittedEvents[Events.natTypeUpdated].length = 0;
29
33
  };
30
34
  beforeEach(() => {
31
35
  fakePeerConnection = {
@@ -56,6 +60,10 @@ describe('ClusterReachability', () => {
56
60
  clusterReachability.on(Events.clientMediaIpsUpdated, (data: ClientMediaIpsUpdatedEventData) => {
57
61
  emittedEvents[Events.clientMediaIpsUpdated].push(data);
58
62
  });
63
+
64
+ clusterReachability.on(Events.natTypeUpdated, (data: NatTypeUpdatedEventData) => {
65
+ emittedEvents[Events.natTypeUpdated].push(data);
66
+ });
59
67
  });
60
68
 
61
69
  afterEach(() => {
@@ -440,5 +448,43 @@ describe('ClusterReachability', () => {
440
448
  xtls: {result: 'reachable', latencyInMilliseconds: 40},
441
449
  });
442
450
  });
451
+
452
+ it('determines correctly if symmetric-nat is detected', async () => {
453
+ const promise = clusterReachability.start();
454
+
455
+ // generate candidates with duplicate addresses
456
+ await clock.tickAsync(10);
457
+ fakePeerConnection.onicecandidate({candidate: {type: 'srflx', address: 'somePublicIp1', relatedPort: 3478, port: 1000}});
458
+
459
+ // check events emitted: there shouldn't be any natTypeUpdated emitted
460
+ assert.equal(emittedEvents[Events.natTypeUpdated].length, 0);
461
+
462
+ await clock.tickAsync(10);
463
+ fakePeerConnection.onicecandidate({candidate: {type: 'srflx', address: 'somePublicIp1', relatedPort: 3478, port: 2000}});
464
+
465
+ // should emit natTypeUpdated event
466
+ assert.equal(emittedEvents[Events.natTypeUpdated].length, 1);
467
+ assert.deepEqual(emittedEvents[Events.natTypeUpdated][0], {
468
+ natType: 'symmetric-nat',
469
+ });
470
+
471
+ // send also a relay candidate so that the reachability check finishes
472
+ fakePeerConnection.onicecandidate({candidate: {type: 'relay', address: 'someTurnRelayIp'}});
473
+ fakePeerConnection.onicecandidate({
474
+ candidate: {type: 'relay', address: 'someTurnRelayIp', port: 443},
475
+ });
476
+
477
+ await promise;
478
+
479
+ assert.deepEqual(clusterReachability.getResult(), {
480
+ udp: {
481
+ result: 'reachable',
482
+ latencyInMilliseconds: 10,
483
+ clientMediaIPs: ['somePublicIp1'],
484
+ },
485
+ tcp: {result: 'reachable', latencyInMilliseconds: 20},
486
+ xtls: {result: 'reachable', latencyInMilliseconds: 20},
487
+ });
488
+ });
443
489
  });
444
490
  });
@@ -2156,6 +2156,7 @@ describe('getReachabilityMetrics', () => {
2156
2156
  reachability_vmn_tcp_failed: 0,
2157
2157
  reachability_vmn_xtls_success: 0,
2158
2158
  reachability_vmn_xtls_failed: 0,
2159
+ natType: 'unknown'
2159
2160
  });
2160
2161
  });
2161
2162
 
@@ -2223,6 +2224,7 @@ describe('getReachabilityMetrics', () => {
2223
2224
  reachability_vmn_tcp_failed: 1,
2224
2225
  reachability_vmn_xtls_success: 0,
2225
2226
  reachability_vmn_xtls_failed: 0,
2227
+ natType: 'unknown'
2226
2228
  }
2227
2229
  );
2228
2230
  });
@@ -2284,6 +2286,7 @@ describe('getReachabilityMetrics', () => {
2284
2286
  reachability_vmn_tcp_failed: 0,
2285
2287
  reachability_vmn_xtls_success: 0,
2286
2288
  reachability_vmn_xtls_failed: 0,
2289
+ natType: 'unknown'
2287
2290
  }
2288
2291
  );
2289
2292
  });
@@ -2345,6 +2348,7 @@ describe('getReachabilityMetrics', () => {
2345
2348
  reachability_vmn_tcp_failed: 3,
2346
2349
  reachability_vmn_xtls_success: 1,
2347
2350
  reachability_vmn_xtls_failed: 1,
2351
+ natType: 'unknown'
2348
2352
  }
2349
2353
  );
2350
2354
  });