@webex/plugin-meetings 2.13.0 → 2.14.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/plugin-meetings",
3
- "version": "2.13.0",
3
+ "version": "2.14.0",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "contributors": [
@@ -24,19 +24,19 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@babel/runtime-corejs2": "^7.14.8",
27
- "@webex/webex-core": "2.13.0",
28
- "@webex/internal-plugin-mercury": "2.13.0",
29
- "@webex/internal-plugin-conversation": "2.13.0",
27
+ "@webex/webex-core": "2.14.0",
28
+ "@webex/internal-plugin-mercury": "2.14.0",
29
+ "@webex/internal-plugin-conversation": "2.14.0",
30
30
  "webrtc-adapter": "^7.7.0",
31
31
  "lodash": "^4.17.21",
32
32
  "uuid": "^3.3.2",
33
33
  "global": "^4.4.0",
34
34
  "ip-anonymize": "^0.1.0",
35
- "@webex/common": "2.13.0",
35
+ "@webex/common": "2.14.0",
36
36
  "bowser": "^2.11.0",
37
37
  "sdp-transform": "^2.12.0",
38
38
  "readable-stream": "^3.6.0",
39
- "@webex/common-timers": "2.13.0",
39
+ "@webex/common-timers": "2.14.0",
40
40
  "btoa": "^1.2.1",
41
41
  "@webex/internal-media-core": "^0.0.6-beta",
42
42
  "javascript-state-machine": "^3.1.0",
@@ -0,0 +1,206 @@
1
+ /* eslint-disable no-param-reassign */
2
+ import {Media as WebRTCMedia} from '@webex/internal-media-core';
3
+
4
+ import BEHAVIORAL_METRICS from '../metrics/constants';
5
+ import Metrics from '../metrics';
6
+ import MediaUtil from '../media/util';
7
+ import LoggerProxy from '../common/logs/logger-proxy';
8
+ import {BNR_STATUS} from '../constants';
9
+
10
+ const createEffectsState = (type) => {
11
+ LoggerProxy.logger.info(`Meeting:effectState#createEffectsState --> creating effectsState for effect ${type}`);
12
+
13
+ return new EffectsState(type);
14
+ };
15
+
16
+ /* The purpose of this class is to manage the effects state(for eg., BNR).
17
+ */
18
+ class EffectsState {
19
+ constructor(type) {
20
+ this.effectType = type;
21
+ this.state = {
22
+ bnr: {
23
+ enabled: BNR_STATUS.NOT_ENABLED
24
+ },
25
+ callToWebrtcBNRInProgress: false
26
+ };
27
+ // these 2 hold the resolve, reject methods for the promise we returned to the client in last handleClientRequest() call
28
+ this.pendingPromiseResolve = null;
29
+ this.pendingPromiseReject = null;
30
+ }
31
+
32
+ /**
33
+ * @memberof EffectsState
34
+ * @param {Boolean} [isEnable] true for enableBNR, false for disableBNR request
35
+ * @param {Object} [meeting] the meeting object
36
+ * @returns {Promise}
37
+ */
38
+ async handleClientRequest(isEnable, meeting) {
39
+ return new Promise((resolve, reject) => {
40
+ if (this.pendingPromiseResolve) {
41
+ // resolve the last promise we returned to the client as the client has issued a new request that has superseded the previous one
42
+ this.pendingPromiseResolve();
43
+ }
44
+ this.pendingPromiseResolve = resolve;
45
+ this.pendingPromiseReject = reject;
46
+
47
+ if (isEnable) this.enableBNR(meeting);
48
+ else this.disableBNR(meeting);
49
+ });
50
+ }
51
+
52
+ /**
53
+ * Internal API to return status of BNR
54
+ * @memberof EffectsState
55
+ * @returns {Boolean}
56
+ * @public
57
+ * @memberof Meeting
58
+ */
59
+ isBnrEnabled() {
60
+ return this.state.bnr.enabled === BNR_STATUS.ENABLED;
61
+ }
62
+
63
+ resolvePromise() {
64
+ if (this.pendingPromiseResolve) {
65
+ this.pendingPromiseResolve(true);
66
+ }
67
+ this.pendingPromiseResolve = null;
68
+ this.pendingPromiseReject = null;
69
+ }
70
+
71
+ rejectPromise(e) {
72
+ if (this.pendingPromiseReject) {
73
+ this.pendingPromiseReject(e);
74
+ }
75
+ this.pendingPromiseResolve = null;
76
+ this.pendingPromiseReject = null;
77
+ }
78
+
79
+ /**
80
+ * enableBNR API
81
+ * @param {Object} meeting the meeting object
82
+ * @returns {Promise<Boolean>}
83
+ * @public
84
+ * @memberof EffectsState
85
+ */
86
+ async enableBNR(meeting) {
87
+ LoggerProxy.logger.info('Meeting:effectState#enableBNR. Enable BNR called');
88
+
89
+ if (this.isBnrEnabled()) {
90
+ LoggerProxy.logger.warn('Meeting:index#enableBNR. BNR is already enabled');
91
+
92
+ return this.resolvePromise();
93
+ }
94
+
95
+ if (this.state.callToWebrtcBNRInProgress) {
96
+ LoggerProxy.logger.warn('Meeting:effectState#enableBNR. Call to WebRTC in progress, we need to wait for it to complete');
97
+
98
+ return this.resolvePromise();
99
+ }
100
+
101
+ const {bnr} = this.state;
102
+
103
+ try {
104
+ bnr.enabled = BNR_STATUS.SHOULD_ENABLE;
105
+ this.state.callToWebrtcBNRInProgress = true;
106
+ const audioStream = MediaUtil.createMediaStream([meeting.mediaProperties.audioTrack]);
107
+
108
+ LoggerProxy.logger.info('Meeting:effectState#enableBNR. MediaStream created from meeting & sent to updateAudio');
109
+ await meeting.updateAudio({
110
+ sendAudio: true,
111
+ receiveAudio: meeting.mediaProperties.mediaDirection.receiveAudio,
112
+ stream: audioStream,
113
+ bnrEnabled: bnr.enabled
114
+ });
115
+
116
+ LoggerProxy.logger.info('Meeting:effectState#enableBNR. Updated meeting audio with bnr enabled track');
117
+ bnr.enabled = BNR_STATUS.ENABLED;
118
+ this.state.callToWebrtcBNRInProgress = false;
119
+ Metrics.sendBehavioralMetric(
120
+ BEHAVIORAL_METRICS.ENABLE_BNR_SUCCESS,
121
+ );
122
+ }
123
+ catch (error) {
124
+ bnr.enabled = BNR_STATUS.NOT_ENABLED;
125
+ this.state.callToWebrtcBNRInProgress = false;
126
+ LoggerProxy.logger.error('Meeting:index#enableBNR.', error);
127
+
128
+ Metrics.sendBehavioralMetric(
129
+ BEHAVIORAL_METRICS.ENABLE_BNR_FAILURE,
130
+ {
131
+ reason: error.message,
132
+ stack: error.stack
133
+ }
134
+ );
135
+ this.rejectPromise(error);
136
+
137
+ throw error;
138
+ }
139
+
140
+ return this.resolvePromise();
141
+ }
142
+
143
+ /**
144
+ * disableBNR API
145
+ * @param {Object} meeting the meeting object
146
+ * @returns {Promise<Boolean>}
147
+ * @public
148
+ * @memberof EffectsState
149
+ */
150
+ async disableBNR(meeting) {
151
+ LoggerProxy.logger.info('Meeting:effectState#disableBNR. Disable BNR called');
152
+
153
+ const {bnr} = this.state;
154
+
155
+ try {
156
+ if (this.state.callToWebrtcBNRInProgress) {
157
+ LoggerProxy.logger.info('Meeting:effectState#disableBNR. Call to WebRTC in progress, we need to wait for it to complete');
158
+
159
+ return this.resolvePromise();
160
+ }
161
+
162
+ bnr.enabled = BNR_STATUS.SHOULD_DISABLE;
163
+ this.state.callToWebrtcBNRInProgress = true;
164
+
165
+ const audioTrack = WebRTCMedia.Effects.BNR.disableBNR(meeting.mediaProperties.audioTrack);
166
+
167
+ const audioStream = MediaUtil.createMediaStream([audioTrack]);
168
+
169
+ LoggerProxy.logger.info('Meeting:effectState#disableBNR. Raw media track obtained from WebRTC & sent to updateAudio');
170
+
171
+ await meeting.updateAudio({
172
+ sendAudio: true,
173
+ receiveAudio: meeting.mediaProperties.mediaDirection.receiveAudio,
174
+ stream: audioStream
175
+ });
176
+
177
+ bnr.enabled = BNR_STATUS.NOT_ENABLED;
178
+
179
+ this.state.callToWebrtcBNRInProgress = false;
180
+
181
+ Metrics.sendBehavioralMetric(
182
+ BEHAVIORAL_METRICS.DISABLE_BNR_SUCCESS
183
+ );
184
+ }
185
+ catch (error) {
186
+ bnr.enabled = BNR_STATUS.ENABLED;
187
+ this.state.callToWebrtcBNRInProgress = false;
188
+ LoggerProxy.logger.error(`Meeting:index#disableBNR. ${error}`);
189
+
190
+ Metrics.sendBehavioralMetric(
191
+ BEHAVIORAL_METRICS.DISABLE_BNR_FAILURE,
192
+ {
193
+ reason: error.message,
194
+ stack: error.stack
195
+ }
196
+ );
197
+ this.rejectPromise(error);
198
+
199
+ throw error;
200
+ }
201
+
202
+ return this.resolvePromise();
203
+ }
204
+ }
205
+
206
+ export default createEffectsState;
@@ -16,6 +16,7 @@ import Media from '../media';
16
16
  import MediaProperties from '../media/properties';
17
17
  import MeetingStateMachine from '../meeting/state';
18
18
  import createMuteState from '../meeting/muteState';
19
+ import createEffectsState from '../meeting/effectsState';
19
20
  import LocusInfo from '../locus-info';
20
21
  import PeerConnectionManager from '../peer-connection-manager';
21
22
  import Metrics from '../metrics';
@@ -531,6 +532,14 @@ export default class Meeting extends StatelessWebexPlugin {
531
532
  * @memberof Meeting
532
533
  */
533
534
  this.video = null;
535
+ /**
536
+ * created later
537
+ * @instance
538
+ * @type {EffectsState}
539
+ * @private
540
+ * @memberof Meeting
541
+ */
542
+ this.effects = null;
534
543
  /**
535
544
  * @instance
536
545
  * @type {MeetingStateMachine}
@@ -915,14 +924,6 @@ export default class Meeting extends StatelessWebexPlugin {
915
924
  */
916
925
  this.meetingInfoFailureReason = undefined;
917
926
 
918
- /**
919
- * Indicates the current status of BNR in the meeting
920
- * @type {BNR_STATUS}
921
- * @private
922
- * @memberof Meeting
923
- */
924
- this.bnrStatus = BNR_STATUS.NOT_ENABLED;
925
-
926
927
  this.setUpLocusInfoListeners();
927
928
  this.locusInfo.init(attrs.locus ? attrs.locus : {});
928
929
  this.hasJoinedOnce = false;
@@ -4495,7 +4496,9 @@ export default class Meeting extends StatelessWebexPlugin {
4495
4496
  if (!this.canUpdateMedia()) {
4496
4497
  return this.enqueueMediaUpdate(MEDIA_UPDATE_TYPE.AUDIO, options);
4497
4498
  }
4498
- const {sendAudio, receiveAudio, stream} = options;
4499
+ const {
4500
+ sendAudio, receiveAudio, stream, bnrEnabled
4501
+ } = options;
4499
4502
  const {audioTransceiver} = this.mediaProperties.peerConnection;
4500
4503
  let track = MeetingUtil.getTrack(stream).audioTrack;
4501
4504
 
@@ -4503,9 +4506,10 @@ export default class Meeting extends StatelessWebexPlugin {
4503
4506
  return Promise.reject(new ParameterError('Pass sendAudio and receiveAudio parameter'));
4504
4507
  }
4505
4508
 
4506
- if (sendAudio && !this.isAudioMuted() && (this.bnrStatus === BNR_STATUS.ENABLED || this.bnrStatus === BNR_STATUS.SHOULD_ENABLE)) {
4509
+ if (sendAudio && !this.isAudioMuted() && (bnrEnabled === BNR_STATUS.ENABLED || bnrEnabled === BNR_STATUS.SHOULD_ENABLE)) {
4510
+ LoggerProxy.logger.info('Meeting:index#updateAudio. Calling WebRTC enable bnr method');
4507
4511
  track = await this.internal_enableBNR(track);
4508
- this.bnrStatus = BNR_STATUS.ENABLED;
4512
+ LoggerProxy.logger.info('Meeting:index#updateAudio. WebRTC enable bnr request completed');
4509
4513
  }
4510
4514
 
4511
4515
  return MeetingUtil.validateOptions({sendAudio, localStream: stream})
@@ -5771,7 +5775,7 @@ export default class Meeting extends StatelessWebexPlugin {
5771
5775
  * @memberof Meeting
5772
5776
  */
5773
5777
  isBnrEnabled() {
5774
- return this.bnrStatus === BNR_STATUS.ENABLED;
5778
+ return this.effects && this.effects.isBnrEnabled();
5775
5779
  }
5776
5780
 
5777
5781
  /**
@@ -5797,109 +5801,72 @@ export default class Meeting extends StatelessWebexPlugin {
5797
5801
  }
5798
5802
 
5799
5803
  /**
5800
- * enableBNR API
5801
- * @returns {Promise<Boolean>}
5804
+ * Enable the audio track with BNR for a meeting
5805
+ * @returns {Promise} resolves the data from enable bnr or rejects if there is no audio or audio is muted
5802
5806
  * @public
5803
5807
  * @memberof Meeting
5804
5808
  */
5805
- async enableBNR() {
5806
- LoggerProxy.logger.info('Meeting:index#enableBNR. Enable BNR called');
5807
- let isSuccess = false;
5808
-
5809
- try {
5810
- if (typeof this.mediaProperties === 'undefined' || typeof this.mediaProperties.audioTrack === 'undefined') {
5811
- throw new Error("Meeting doesn't have an audioTrack attached");
5812
- }
5813
- else if (this.isAudioMuted()) {
5814
- throw new Error('Cannot enable BNR while meeting is muted');
5815
- }
5809
+ enableBNR() {
5810
+ if (typeof this.mediaProperties === 'undefined' || typeof this.mediaProperties.audioTrack === 'undefined') {
5811
+ return Promise.reject(new Error("Meeting doesn't have an audioTrack attached"));
5812
+ }
5816
5813
 
5814
+ if (this.isAudioMuted()) {
5815
+ return Promise.reject(new Error('Cannot enable BNR while meeting is muted'));
5816
+ }
5817
5817
 
5818
- this.bnrStatus = BNR_STATUS.SHOULD_ENABLE;
5818
+ this.effects = this.effects || createEffectsState('BNR');
5819
5819
 
5820
- const audioStream = MediaUtil.createMediaStream([this.mediaProperties.audioTrack]);
5820
+ const LOG_HEADER = 'Meeting:index#enableBNR -->';
5821
5821
 
5822
- LoggerProxy.logger.info('Meeting:index#enableBNR. MediaStream created from meeting & sent to updateAudio');
5823
- await this.updateAudio({
5824
- sendAudio: true,
5825
- receiveAudio: this.mediaProperties.mediaDirection.receiveAudio,
5826
- stream: audioStream
5827
- });
5828
- this.bnrStatus = BNR_STATUS.ENABLED;
5829
- isSuccess = true;
5830
- Metrics.sendBehavioralMetric(
5831
- BEHAVIORAL_METRICS.ENABLE_BNR_SUCCESS,
5832
- );
5833
- }
5834
- catch (error) {
5835
- this.bnrStatus = BNR_STATUS.NOT_ENABLED;
5836
- Metrics.sendBehavioralMetric(
5837
- BEHAVIORAL_METRICS.ENABLE_BNR_FAILURE,
5838
- {
5839
- reason: error.message,
5840
- stack: error.stack
5841
- }
5842
- );
5843
- LoggerProxy.logger.error('Meeting:index#enableBNR.', error);
5844
- throw error;
5845
- }
5822
+ return logRequest(this.effects.handleClientRequest(true, this)
5823
+ .then((res) => {
5824
+ LoggerProxy.logger.info('Meeting:index#enableBNR. Enable bnr completed');
5846
5825
 
5847
- return isSuccess;
5826
+ return res;
5827
+ })
5828
+ .catch((error) => {
5829
+ throw error;
5830
+ }),
5831
+ {
5832
+ header: `${LOG_HEADER} enable bnr`,
5833
+ success: `${LOG_HEADER} enable bnr success`,
5834
+ failure: `${LOG_HEADER} enable bnr failure, `
5835
+ });
5848
5836
  }
5849
5837
 
5850
5838
  /**
5851
- * disableBNR API
5852
- * @returns {Promise<Boolean>}
5839
+ * Disable the BNR for an audio track
5840
+ * @returns {Promise} resolves the data from disable bnr or rejects if there is no audio set
5853
5841
  * @public
5854
5842
  * @memberof Meeting
5855
5843
  */
5856
- async disableBNR() {
5857
- LoggerProxy.logger.info('Meeting:index#disableBNR. Disable BNR called');
5858
- let isSuccess = false;
5859
-
5860
- try {
5861
- if (!this.isBnrEnabled()) {
5862
- throw new Error('Can not disable as BNR is not enabled');
5863
- }
5864
- else if (typeof this.mediaProperties === 'undefined' || typeof this.mediaProperties.audioTrack === 'undefined') {
5865
- throw new Error("Meeting doesn't have an audioTrack attached");
5866
- }
5867
- const audioTrack = WebRTCMedia.Effects.BNR.disableBNR(this.mediaProperties.audioTrack);
5868
- const audioStream = MediaUtil.createMediaStream([audioTrack]);
5869
-
5870
- LoggerProxy.logger.info('Meeting:index#disableBNR. Raw media track obtained from WebRTC & sent to updateAudio');
5871
-
5872
- this.bnrStatus = BNR_STATUS.SHOULD_DISABLE;
5873
-
5874
- await this.updateAudio({
5875
- sendAudio: true,
5876
- receiveAudio: this.mediaProperties.mediaDirection.receiveAudio,
5877
- stream: audioStream
5878
- });
5879
-
5880
- this.bnrStatus = BNR_STATUS.NOT_ENABLED;
5881
-
5882
- isSuccess = true;
5844
+ disableBNR() {
5845
+ if (typeof this.mediaProperties === 'undefined' || typeof this.mediaProperties.audioTrack === 'undefined') {
5846
+ return Promise.reject(new Error("Meeting doesn't have an audioTrack attached"));
5847
+ }
5883
5848
 
5884
- Metrics.sendBehavioralMetric(
5885
- BEHAVIORAL_METRICS.DISABLE_BNR_SUCCESS
5886
- );
5849
+ if (!this.isBnrEnabled()) {
5850
+ return Promise.reject(new Error('Can not disable as BNR is not enabled'));
5887
5851
  }
5888
- catch (error) {
5889
- this.bnrStatus = BNR_STATUS.ENABLED;
5890
- LoggerProxy.logger.error(`Meeting:index#disableBNR. ${error}`);
5891
5852
 
5892
- Metrics.sendBehavioralMetric(
5893
- BEHAVIORAL_METRICS.DISABLE_BNR_FAILURE,
5894
- {
5895
- reason: error.message,
5896
- stack: error.stack
5897
- }
5898
- );
5853
+ this.effects = this.effects || createEffectsState('BNR');
5899
5854
 
5900
- throw error;
5901
- }
5855
+ const LOG_HEADER = 'Meeting:index#disableBNR -->';
5856
+
5857
+ return logRequest(this.effects.handleClientRequest(false, this)
5858
+ .then((res) => {
5859
+ LoggerProxy.logger.info('Meeting:index#disableBNR. Disable bnr completed');
5902
5860
 
5903
- return isSuccess;
5861
+ return res;
5862
+ })
5863
+ .catch((error) => {
5864
+ throw error;
5865
+ }),
5866
+ {
5867
+ header: `${LOG_HEADER} disable bnr`,
5868
+ success: `${LOG_HEADER} disable bnr success`,
5869
+ failure: `${LOG_HEADER} disable bnr failure, `
5870
+ });
5904
5871
  }
5905
5872
  }