@webex/plugin-meetings 3.0.0-beta.307 → 3.0.0-beta.308

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.
@@ -1,3 +1,4 @@
1
+ type Enum<T extends Record<string, unknown>> = T[keyof T];
1
2
  export declare const AUDIO = "audio";
2
3
  export declare const AUDIO_STATUS = "audioStatus";
3
4
  export declare const ALERT = "alert";
@@ -866,10 +867,11 @@ export declare const MediaContent: {
866
867
  slides: string;
867
868
  };
868
869
  export declare const NETWORK_STATUS: {
869
- DISCONNECTED: string;
870
- RECONNECTING: string;
871
- CONNECTED: string;
870
+ readonly DISCONNECTED: "DISCONNECTED";
871
+ readonly RECONNECTING: "RECONNECTING";
872
+ readonly CONNECTED: "CONNECTED";
872
873
  };
874
+ export type NETWORK_STATUS = Enum<typeof NETWORK_STATUS>;
873
875
  export declare const NETWORK_TYPE: {
874
876
  VPN: string;
875
877
  UNKNOWN: string;
@@ -1061,6 +1063,7 @@ export declare const IP_VERSION: {
1061
1063
  readonly only_ipv6: 6;
1062
1064
  readonly ipv4_and_ipv6: 1;
1063
1065
  };
1064
- export type IP_VERSION = (typeof IP_VERSION)[keyof typeof IP_VERSION];
1066
+ export type IP_VERSION = Enum<typeof IP_VERSION>;
1065
1067
  export declare const MEETING_PERMISSION_TOKEN_REFRESH_THRESHOLD_IN_SEC = 30;
1066
1068
  export declare const MEETING_PERMISSION_TOKEN_REFRESH_REASON = "ttl-join";
1069
+ export {};
@@ -11,6 +11,7 @@ import ReconnectionManager from '../reconnection-manager';
11
11
  import MeetingRequest from './request';
12
12
  import Members from '../members/index';
13
13
  import Transcription from '../transcription';
14
+ import { NETWORK_STATUS } from '../constants';
14
15
  import { ReceiveSlotManager } from '../multistream/receiveSlotManager';
15
16
  import { MediaRequestManager } from '../multistream/mediaRequestManager';
16
17
  import { Configuration as RemoteMediaManagerConfiguration, RemoteMediaManager } from '../multistream/remoteMediaManager';
@@ -358,7 +359,7 @@ export default class Meeting extends StatelessWebexPlugin {
358
359
  meetingInfoFailureCode?: number;
359
360
  meetingInfoExtraParams?: Record<string, any>;
360
361
  networkQualityMonitor: NetworkQualityMonitor;
361
- networkStatus: string;
362
+ networkStatus?: NETWORK_STATUS;
362
363
  passwordStatus: string;
363
364
  queuedMediaUpdates: any[];
364
365
  recording: any;
@@ -533,7 +534,7 @@ export default class Meeting extends StatelessWebexPlugin {
533
534
  private setUpLocusFullStateListener;
534
535
  /**
535
536
  * sets the network status on meeting object
536
- * @param {String} networkStatus
537
+ * @param {NETWORK_STATUS} networkStatus
537
538
  * @private
538
539
  * @returns {undefined}
539
540
  * @memberof Meeting
@@ -62,7 +62,7 @@ var Webinar = _webexCore.WebexPlugin.extend({
62
62
  updateCanManageWebcast: function updateCanManageWebcast(canManageWebcast) {
63
63
  this.set('canManageWebcast', canManageWebcast);
64
64
  },
65
- version: "3.0.0-beta.307"
65
+ version: "3.0.0-beta.308"
66
66
  });
67
67
  var _default = Webinar;
68
68
  exports.default = _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/plugin-meetings",
3
- "version": "3.0.0-beta.307",
3
+ "version": "3.0.0-beta.308",
4
4
  "description": "",
5
5
  "license": "Cisco EULA (https://www.cisco.com/c/en/us/products/end-user-license-agreement.html)",
6
6
  "contributors": [
@@ -32,12 +32,12 @@
32
32
  "build": "yarn run -T tsc --declaration true --declarationDir ./dist/types"
33
33
  },
34
34
  "devDependencies": {
35
- "@webex/plugin-meetings": "3.0.0-beta.307",
36
- "@webex/test-helper-chai": "3.0.0-beta.307",
37
- "@webex/test-helper-mocha": "3.0.0-beta.307",
38
- "@webex/test-helper-mock-webex": "3.0.0-beta.307",
39
- "@webex/test-helper-retry": "3.0.0-beta.307",
40
- "@webex/test-helper-test-users": "3.0.0-beta.307",
35
+ "@webex/plugin-meetings": "3.0.0-beta.308",
36
+ "@webex/test-helper-chai": "3.0.0-beta.308",
37
+ "@webex/test-helper-mocha": "3.0.0-beta.308",
38
+ "@webex/test-helper-mock-webex": "3.0.0-beta.308",
39
+ "@webex/test-helper-retry": "3.0.0-beta.308",
40
+ "@webex/test-helper-test-users": "3.0.0-beta.308",
41
41
  "chai": "^4.3.4",
42
42
  "chai-as-promised": "^7.1.1",
43
43
  "jsdom-global": "3.0.2",
@@ -46,19 +46,19 @@
46
46
  "typescript": "^4.7.4"
47
47
  },
48
48
  "dependencies": {
49
- "@webex/common": "3.0.0-beta.307",
49
+ "@webex/common": "3.0.0-beta.308",
50
50
  "@webex/internal-media-core": "2.2.1",
51
- "@webex/internal-plugin-conversation": "3.0.0-beta.307",
52
- "@webex/internal-plugin-device": "3.0.0-beta.307",
53
- "@webex/internal-plugin-llm": "3.0.0-beta.307",
54
- "@webex/internal-plugin-mercury": "3.0.0-beta.307",
55
- "@webex/internal-plugin-metrics": "3.0.0-beta.307",
56
- "@webex/internal-plugin-support": "3.0.0-beta.307",
57
- "@webex/internal-plugin-user": "3.0.0-beta.307",
58
- "@webex/media-helpers": "3.0.0-beta.307",
59
- "@webex/plugin-people": "3.0.0-beta.307",
60
- "@webex/plugin-rooms": "3.0.0-beta.307",
61
- "@webex/webex-core": "3.0.0-beta.307",
51
+ "@webex/internal-plugin-conversation": "3.0.0-beta.308",
52
+ "@webex/internal-plugin-device": "3.0.0-beta.308",
53
+ "@webex/internal-plugin-llm": "3.0.0-beta.308",
54
+ "@webex/internal-plugin-mercury": "3.0.0-beta.308",
55
+ "@webex/internal-plugin-metrics": "3.0.0-beta.308",
56
+ "@webex/internal-plugin-support": "3.0.0-beta.308",
57
+ "@webex/internal-plugin-user": "3.0.0-beta.308",
58
+ "@webex/media-helpers": "3.0.0-beta.308",
59
+ "@webex/plugin-people": "3.0.0-beta.308",
60
+ "@webex/plugin-rooms": "3.0.0-beta.308",
61
+ "@webex/webex-core": "3.0.0-beta.308",
62
62
  "ampersand-collection": "^2.0.2",
63
63
  "bowser": "^2.11.0",
64
64
  "btoa": "^1.2.1",
package/src/constants.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  // @ts-ignore
2
2
  import {hydraTypes} from '@webex/common';
3
3
 
4
+ type Enum<T extends Record<string, unknown>> = T[keyof T];
5
+
4
6
  // *********** LOWERCASE / CAMELCASE STRINGS ************
5
7
 
6
8
  export const AUDIO = 'audio';
@@ -1070,7 +1072,9 @@ export const NETWORK_STATUS = {
1070
1072
  DISCONNECTED: 'DISCONNECTED',
1071
1073
  RECONNECTING: 'RECONNECTING',
1072
1074
  CONNECTED: 'CONNECTED',
1073
- };
1075
+ } as const;
1076
+
1077
+ export type NETWORK_STATUS = Enum<typeof NETWORK_STATUS>;
1074
1078
 
1075
1079
  export const NETWORK_TYPE = {
1076
1080
  VPN: 'vpn',
@@ -1286,7 +1290,7 @@ export const IP_VERSION = {
1286
1290
  ipv4_and_ipv6: 1,
1287
1291
  } as const;
1288
1292
 
1289
- export type IP_VERSION = (typeof IP_VERSION)[keyof typeof IP_VERSION];
1293
+ export type IP_VERSION = Enum<typeof IP_VERSION>;
1290
1294
 
1291
1295
  // constant for if the permissionToken is about to expire in the next 30 seconds, refresh it
1292
1296
  export const MEETING_PERMISSION_TOKEN_REFRESH_THRESHOLD_IN_SEC = 30;
@@ -528,7 +528,7 @@ export default class Meeting extends StatelessWebexPlugin {
528
528
  meetingInfoFailureCode?: number;
529
529
  meetingInfoExtraParams?: Record<string, any>;
530
530
  networkQualityMonitor: NetworkQualityMonitor;
531
- networkStatus: string;
531
+ networkStatus?: NETWORK_STATUS;
532
532
  passwordStatus: string;
533
533
  queuedMediaUpdates: any[];
534
534
  recording: any;
@@ -1095,13 +1095,14 @@ export default class Meeting extends StatelessWebexPlugin {
1095
1095
  */
1096
1096
  this.networkQualityMonitor = null;
1097
1097
  /**
1098
+ * Indicates network status of the webrtc media connection
1098
1099
  * @instance
1099
1100
  * @type {String}
1100
1101
  * @readonly
1101
1102
  * @public
1102
1103
  * @memberof Meeting
1103
1104
  */
1104
- this.networkStatus = null;
1105
+ this.networkStatus = undefined;
1105
1106
  /**
1106
1107
  * Passing only info as we send basic info for meeting added event
1107
1108
  * @instance
@@ -1927,12 +1928,12 @@ export default class Meeting extends StatelessWebexPlugin {
1927
1928
 
1928
1929
  /**
1929
1930
  * sets the network status on meeting object
1930
- * @param {String} networkStatus
1931
+ * @param {NETWORK_STATUS} networkStatus
1931
1932
  * @private
1932
1933
  * @returns {undefined}
1933
1934
  * @memberof Meeting
1934
1935
  */
1935
- private setNetworkStatus(networkStatus: string) {
1936
+ private setNetworkStatus(networkStatus?: NETWORK_STATUS) {
1936
1937
  if (networkStatus === NETWORK_STATUS.DISCONNECTED) {
1937
1938
  Trigger.trigger(
1938
1939
  this,
@@ -3907,6 +3908,7 @@ export default class Meeting extends StatelessWebexPlugin {
3907
3908
  this.receiveSlotManager.reset();
3908
3909
  this.mediaProperties.webrtcMediaConnection.close();
3909
3910
  this.sendSlotManager.reset();
3911
+ this.setNetworkStatus(undefined);
3910
3912
  }
3911
3913
 
3912
3914
  this.audio = null;
@@ -5445,6 +5447,10 @@ export default class Meeting extends StatelessWebexPlugin {
5445
5447
  // @ts-ignore
5446
5448
  this.webex.internal.newMetrics.submitClientEvent({
5447
5449
  name: 'client.ice.end',
5450
+ payload: {
5451
+ canProceed: true,
5452
+ icePhase: !this.networkStatus ? 'JOIN_MEETING_FINAL' : 'IN_MEETING',
5453
+ },
5448
5454
  options: {
5449
5455
  meetingId: this.id,
5450
5456
  },
@@ -5633,10 +5633,13 @@ describe('plugin-meetings', () => {
5633
5633
  });
5634
5634
 
5635
5635
  describe('submitClientEvent on connectionSuccess', () => {
5636
- it('sends client.ice.end when connectionSuccess on CONNECTION_STATE_CHANGED event', () => {
5636
+ let setNetworkStatusSpy;
5637
+
5638
+ const setupSpies = () => {
5639
+ setNetworkStatusSpy = sinon.spy(meeting, 'setNetworkStatus');
5640
+
5637
5641
  meeting.reconnectionManager = new ReconnectionManager(meeting);
5638
5642
  meeting.reconnectionManager.iceReconnected = sinon.stub().returns(undefined);
5639
- meeting.setNetworkStatus = sinon.stub().returns(undefined);
5640
5643
  meeting.statsAnalyzer = {startAnalyzer: sinon.stub()};
5641
5644
  meeting.mediaProperties.webrtcMediaConnection = {
5642
5645
  // mock the on() method and store all the listeners
@@ -5644,17 +5647,19 @@ describe('plugin-meetings', () => {
5644
5647
  eventListeners[event] = listener;
5645
5648
  }),
5646
5649
  };
5650
+ };
5647
5651
 
5648
- meeting.setupMediaConnectionListeners();
5649
- eventListeners[Event.CONNECTION_STATE_CHANGED]({
5650
- state: 'Connected',
5651
- });
5652
+ const checkExpectedSpies = (expected) => {
5652
5653
  assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
5653
5654
  assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
5654
5655
  name: 'client.ice.end',
5655
5656
  options: {
5656
5657
  meetingId: meeting.id,
5657
5658
  },
5659
+ payload: {
5660
+ canProceed: true,
5661
+ icePhase: expected.icePhase,
5662
+ },
5658
5663
  });
5659
5664
  assert.calledOnce(Metrics.sendBehavioralMetric);
5660
5665
  assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.CONNECTION_SUCCESS, {
@@ -5662,14 +5667,54 @@ describe('plugin-meetings', () => {
5662
5667
  locus_id: meeting.locusId,
5663
5668
  latency: undefined,
5664
5669
  });
5665
- assert.calledOnce(meeting.setNetworkStatus);
5666
- assert.calledWith(meeting.setNetworkStatus, NETWORK_STATUS.CONNECTED);
5670
+ assert.deepEqual(
5671
+ setNetworkStatusSpy.getCalls().map((call) => call.args[0]),
5672
+ expected.setNetworkStatusCallParams
5673
+ );
5667
5674
  assert.calledOnce(meeting.reconnectionManager.iceReconnected);
5668
5675
  assert.calledOnce(meeting.statsAnalyzer.startAnalyzer);
5669
5676
  assert.calledWith(
5670
5677
  meeting.statsAnalyzer.startAnalyzer,
5671
5678
  meeting.mediaProperties.webrtcMediaConnection
5672
5679
  );
5680
+ };
5681
+
5682
+ const resetSpies = () => {
5683
+ setNetworkStatusSpy.resetHistory();
5684
+ webex.internal.newMetrics.submitClientEvent.resetHistory();
5685
+ Metrics.sendBehavioralMetric.resetHistory();
5686
+ meeting.reconnectionManager.iceReconnected.resetHistory();
5687
+ meeting.statsAnalyzer.startAnalyzer.resetHistory();
5688
+ };
5689
+
5690
+ it('sends client.ice.end with the correct icePhase when we get ConnectionState.Connected on CONNECTION_STATE_CHANGED event', () => {
5691
+ setupSpies();
5692
+
5693
+ meeting.setupMediaConnectionListeners();
5694
+
5695
+ // simulate first connection success
5696
+ eventListeners[Event.CONNECTION_STATE_CHANGED]({
5697
+ state: 'Connected',
5698
+ });
5699
+ checkExpectedSpies({
5700
+ icePhase: 'JOIN_MEETING_FINAL',
5701
+ setNetworkStatusCallParams: [NETWORK_STATUS.CONNECTED],
5702
+ });
5703
+
5704
+ // now simulate short connection loss, the 2nd client.ice.end should have a different icePhase
5705
+ resetSpies();
5706
+
5707
+ eventListeners[Event.CONNECTION_STATE_CHANGED]({
5708
+ state: 'Disconnected',
5709
+ });
5710
+ eventListeners[Event.CONNECTION_STATE_CHANGED]({
5711
+ state: 'Connected',
5712
+ });
5713
+
5714
+ checkExpectedSpies({
5715
+ icePhase: 'IN_MEETING',
5716
+ setNetworkStatusCallParams: [NETWORK_STATUS.DISCONNECTED, NETWORK_STATUS.CONNECTED],
5717
+ });
5673
5718
  });
5674
5719
  });
5675
5720
 
@@ -6931,12 +6976,14 @@ describe('plugin-meetings', () => {
6931
6976
  });
6932
6977
  describe('#closePeerConnections', () => {
6933
6978
  it('should close the webrtc media connection, and return a promise', async () => {
6979
+ const setNetworkStatusSpy = sinon.spy(meeting, 'setNetworkStatus');
6934
6980
  meeting.mediaProperties.webrtcMediaConnection = {close: sinon.stub()};
6935
6981
  const pcs = meeting.closePeerConnections();
6936
6982
 
6937
6983
  assert.exists(pcs.then);
6938
6984
  await pcs;
6939
6985
  assert.calledOnce(meeting.mediaProperties.webrtcMediaConnection.close);
6986
+ assert.calledOnceWithExactly(setNetworkStatusSpy, undefined);
6940
6987
  });
6941
6988
  });
6942
6989
  describe('#unsetPeerConnections', () => {