@webex/plugin-meetings 3.0.0-beta.35 → 3.0.0-beta.37

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 (55) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/edit-lock-error.js +52 -0
  3. package/dist/breakouts/edit-lock-error.js.map +1 -0
  4. package/dist/breakouts/index.js +86 -2
  5. package/dist/breakouts/index.js.map +1 -1
  6. package/dist/constants.js +12 -1
  7. package/dist/constants.js.map +1 -1
  8. package/dist/media/index.js +4 -18
  9. package/dist/media/index.js.map +1 -1
  10. package/dist/media/properties.js +3 -3
  11. package/dist/media/properties.js.map +1 -1
  12. package/dist/meeting/index.js +194 -306
  13. package/dist/meeting/index.js.map +1 -1
  14. package/dist/meeting/muteState.js +7 -2
  15. package/dist/meeting/muteState.js.map +1 -1
  16. package/dist/meeting/util.js +2 -2
  17. package/dist/meeting/util.js.map +1 -1
  18. package/dist/metrics/constants.js +0 -4
  19. package/dist/metrics/constants.js.map +1 -1
  20. package/dist/reconnection-manager/index.js +1 -2
  21. package/dist/reconnection-manager/index.js.map +1 -1
  22. package/dist/statsAnalyzer/index.js +8 -4
  23. package/dist/statsAnalyzer/index.js.map +1 -1
  24. package/dist/types/breakouts/edit-lock-error.d.ts +15 -0
  25. package/dist/types/constants.d.ts +11 -0
  26. package/dist/types/media/properties.d.ts +7 -6
  27. package/dist/types/meeting/index.d.ts +11 -36
  28. package/dist/types/metrics/constants.d.ts +0 -4
  29. package/package.json +19 -19
  30. package/src/breakouts/README.md +8 -2
  31. package/src/breakouts/edit-lock-error.ts +25 -0
  32. package/src/breakouts/index.ts +73 -0
  33. package/src/constants.ts +11 -0
  34. package/src/media/index.ts +14 -24
  35. package/src/media/properties.ts +16 -10
  36. package/src/meeting/index.ts +122 -204
  37. package/src/meeting/muteState.ts +5 -5
  38. package/src/meeting/util.ts +5 -4
  39. package/src/metrics/constants.ts +0 -4
  40. package/src/reconnection-manager/index.ts +1 -1
  41. package/src/statsAnalyzer/index.ts +4 -4
  42. package/test/integration/spec/converged-space-meetings.js +3 -3
  43. package/test/integration/spec/journey.js +3 -3
  44. package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
  45. package/test/unit/spec/breakouts/index.ts +92 -1
  46. package/test/unit/spec/media/index.ts +8 -6
  47. package/test/unit/spec/meeting/index.js +87 -114
  48. package/test/unit/spec/meeting/muteState.js +21 -22
  49. package/test/unit/spec/meeting/utils.js +3 -1
  50. package/test/utils/testUtils.js +30 -25
  51. package/dist/meeting/effectsState.js +0 -262
  52. package/dist/meeting/effectsState.js.map +0 -1
  53. package/dist/types/meeting/effectsState.d.ts +0 -42
  54. package/src/meeting/effectsState.ts +0 -211
  55. package/test/unit/spec/meeting/effectsState.js +0 -285
@@ -7,7 +7,10 @@ import {
7
7
  Errors,
8
8
  ErrorType,
9
9
  Event,
10
- Media as WebRTCMedia,
10
+ LocalCameraTrack,
11
+ LocalDisplayTrack,
12
+ LocalMicrophoneTrack,
13
+ LocalTrackEvents,
11
14
  MediaType,
12
15
  RemoteTrackType,
13
16
  } from '@webex/internal-media-core';
@@ -28,7 +31,6 @@ import Media from '../media';
28
31
  import MediaProperties from '../media/properties';
29
32
  import MeetingStateMachine from './state';
30
33
  import {createMuteState} from './muteState';
31
- import createEffectsState from './effectsState';
32
34
  import LocusInfo from '../locus-info';
33
35
  import Metrics from '../metrics';
34
36
  import {trigger, mediaType, error as MetricsError, eventType} from '../metrics/config';
@@ -78,7 +80,6 @@ import {
78
80
  SHARE_STOPPED_REASON,
79
81
  VIDEO_RESOLUTIONS,
80
82
  VIDEO,
81
- BNR_STATUS,
82
83
  HTTP_VERBS,
83
84
  } from '../constants';
84
85
  import BEHAVIORAL_METRICS from '../metrics/constants';
@@ -430,7 +431,6 @@ export default class Meeting extends StatelessWebexPlugin {
430
431
  destination: string;
431
432
  destinationType: string;
432
433
  deviceUrl: string;
433
- effects: any;
434
434
  hostId: string;
435
435
  id: string;
436
436
  isMultistream: boolean;
@@ -731,14 +731,6 @@ export default class Meeting extends StatelessWebexPlugin {
731
731
  * @memberof Meeting
732
732
  */
733
733
  this.video = null;
734
- /**
735
- * created later
736
- * @instance
737
- * @type {EffectsState}
738
- * @private
739
- * @memberof Meeting
740
- */
741
- this.effects = null;
742
734
  /**
743
735
  * @instance
744
736
  * @type {MeetingStateMachine}
@@ -1988,10 +1980,14 @@ export default class Meeting extends StatelessWebexPlugin {
1988
1980
  this.selfId === contentShare.beneficiaryId &&
1989
1981
  contentShare.disposition === FLOOR_ACTION.GRANTED
1990
1982
  ) {
1991
- if (this.mediaProperties.shareTrack?.readyState === 'ended') {
1983
+ // @ts-ignore originalTrack is private - this will be fixed when SPARK-399694 are SPARK-399695 done
1984
+ const localShareTrack = this.mediaProperties.shareTrack?.originalTrack;
1985
+
1986
+ // todo: remove this block of code and instead make sure we have LocalTrackEvents.Ended listener always registered (SPARK-399695)
1987
+ if (localShareTrack?.readyState === 'ended') {
1992
1988
  try {
1993
1989
  if (this.isMultistream) {
1994
- await this.unpublishTracks([this.mediaProperties.shareTrack]); // todo screen share audio (SPARK-399690)
1990
+ await this.unpublishTracks([localShareTrack]); // todo screen share audio (SPARK-399690)
1995
1991
  } else {
1996
1992
  await this.stopShare({
1997
1993
  skipSignalingCheck: true,
@@ -2101,7 +2097,8 @@ export default class Meeting extends StatelessWebexPlugin {
2101
2097
  oldShareStatus === SHARE_STATUS.LOCAL_SHARE_ACTIVE
2102
2098
  ) {
2103
2099
  if (this.isMultistream) {
2104
- await this.unpublishTracks([this.mediaProperties.shareTrack]); // todo screen share audio (SPARK-399690)
2100
+ // @ts-ignore originalTrack is private - this will be fixed in SPARK-399694
2101
+ await this.unpublishTracks([this.mediaProperties.shareTrack?.originalTrack]); // todo screen share audio (SPARK-399690)
2105
2102
  } else {
2106
2103
  await this.updateShare({
2107
2104
  sendShare: false,
@@ -2579,8 +2576,7 @@ export default class Meeting extends StatelessWebexPlugin {
2579
2576
  // TODO: Handle sharing and wireless sharing when meeting end
2580
2577
  if (this.wirelessShare) {
2581
2578
  if (this.mediaProperties.shareTrack) {
2582
- this.mediaProperties.shareTrack.onended = null;
2583
- this.mediaProperties.shareTrack.stop();
2579
+ this.setLocalShareTrack(null);
2584
2580
  }
2585
2581
  }
2586
2582
  // when multiple WEB deviceType join with same user
@@ -3064,14 +3060,14 @@ export default class Meeting extends StatelessWebexPlugin {
3064
3060
  this,
3065
3061
  {
3066
3062
  file: 'meeting/index',
3067
- function: 'setLocalTracks',
3063
+ function: 'sendLocalMediaReadyEvent',
3068
3064
  },
3069
3065
  EVENT_TRIGGERS.MEDIA_READY,
3070
3066
  {
3071
3067
  type: EVENT_TYPES.LOCAL,
3072
3068
  stream: MediaUtil.createMediaStream([
3073
- this.mediaProperties.audioTrack,
3074
- this.mediaProperties.videoTrack,
3069
+ this.mediaProperties.audioTrack?.underlyingTrack,
3070
+ this.mediaProperties.videoTrack?.underlyingTrack,
3075
3071
  ]),
3076
3072
  }
3077
3073
  );
@@ -3079,15 +3075,19 @@ export default class Meeting extends StatelessWebexPlugin {
3079
3075
 
3080
3076
  /**
3081
3077
  * Sets the local audio track on the class and emits an event to the developer
3082
- * @param {MediaStreamTrack} audioTrack
3078
+ * @param {MediaStreamTrack} rawAudioTrack
3083
3079
  * @param {Boolean} emitEvent if true, a media ready event is emitted to the developer
3084
3080
  * @returns {undefined}
3085
3081
  * @private
3086
3082
  * @memberof Meeting
3087
3083
  */
3088
- private setLocalAudioTrack(audioTrack: MediaStreamTrack, emitEvent = true) {
3089
- if (audioTrack) {
3090
- const settings = audioTrack.getSettings();
3084
+ private setLocalAudioTrack(rawAudioTrack: MediaStreamTrack | null, emitEvent = true) {
3085
+ if (rawAudioTrack) {
3086
+ const settings = rawAudioTrack.getSettings();
3087
+
3088
+ const localMicrophoneTrack = new LocalMicrophoneTrack(
3089
+ MediaUtil.createMediaStream([rawAudioTrack])
3090
+ );
3091
3091
 
3092
3092
  this.mediaProperties.setMediaSettings('audio', {
3093
3093
  echoCancellation: settings.echoCancellation,
@@ -3098,7 +3098,7 @@ export default class Meeting extends StatelessWebexPlugin {
3098
3098
  'Meeting:index#setLocalAudioTrack --> Audio settings.',
3099
3099
  JSON.stringify(this.mediaProperties.mediaSettings.audio)
3100
3100
  );
3101
- this.mediaProperties.setLocalAudioTrack(audioTrack);
3101
+ this.mediaProperties.setLocalAudioTrack(localMicrophoneTrack);
3102
3102
  if (this.audio) this.audio.applyClientStateLocally(this);
3103
3103
  } else {
3104
3104
  this.mediaProperties.setLocalAudioTrack(null);
@@ -3111,18 +3111,20 @@ export default class Meeting extends StatelessWebexPlugin {
3111
3111
 
3112
3112
  /**
3113
3113
  * Sets the local video track on the class and emits an event to the developer
3114
- * @param {MediaStreamTrack} videoTrack
3114
+ * @param {MediaStreamTrack} rawVideoTrack
3115
3115
  * @param {Boolean} emitEvent if true, a media ready event is emitted to the developer
3116
3116
  * @returns {undefined}
3117
3117
  * @private
3118
3118
  * @memberof Meeting
3119
3119
  */
3120
- private setLocalVideoTrack(videoTrack: MediaStreamTrack, emitEvent = true) {
3121
- if (videoTrack) {
3122
- const {aspectRatio, frameRate, height, width, deviceId} = videoTrack.getSettings();
3120
+ private setLocalVideoTrack(rawVideoTrack: MediaStreamTrack | null, emitEvent = true) {
3121
+ if (rawVideoTrack) {
3122
+ const {aspectRatio, frameRate, height, width, deviceId} = rawVideoTrack.getSettings();
3123
3123
 
3124
3124
  const {localQualityLevel} = this.mediaProperties;
3125
3125
 
3126
+ const localCameraTrack = new LocalCameraTrack(MediaUtil.createMediaStream([rawVideoTrack]));
3127
+
3126
3128
  if (Number(localQualityLevel.slice(0, -1)) > height) {
3127
3129
  LoggerProxy.logger
3128
3130
  .warn(`Meeting:index#setLocalVideoTrack --> Local video quality of ${localQualityLevel} not supported,
@@ -3131,7 +3133,7 @@ export default class Meeting extends StatelessWebexPlugin {
3131
3133
  this.mediaProperties.setLocalQualityLevel(`${height}p`);
3132
3134
  }
3133
3135
 
3134
- this.mediaProperties.setLocalVideoTrack(videoTrack);
3136
+ this.mediaProperties.setLocalVideoTrack(localCameraTrack);
3135
3137
  if (this.video) this.video.applyClientStateLocally(this);
3136
3138
 
3137
3139
  this.mediaProperties.setMediaSettings('video', {
@@ -3166,6 +3168,12 @@ export default class Meeting extends StatelessWebexPlugin {
3166
3168
  */
3167
3169
  public setLocalTracks(localStream: any) {
3168
3170
  if (localStream) {
3171
+ if (this.isMultistream) {
3172
+ throw new Error(
3173
+ 'addMedia() and updateMedia() APIs are not supported with multistream, use publishTracks/unpublishTracks instead'
3174
+ );
3175
+ }
3176
+
3169
3177
  const {audioTrack, videoTrack} = MeetingUtil.getTrack(localStream);
3170
3178
 
3171
3179
  this.setLocalAudioTrack(audioTrack, false);
@@ -3177,24 +3185,29 @@ export default class Meeting extends StatelessWebexPlugin {
3177
3185
 
3178
3186
  /**
3179
3187
  * Sets the local media stream on the class and emits an event to the developer
3180
- * @param {MediaStreamTrack} localShareTrack the local media stream
3188
+ * @param {MediaStreamTrack} rawLocalShareTrack the local share media track
3181
3189
  * @returns {undefined}
3182
3190
  * @public
3183
3191
  * @memberof Meeting
3184
3192
  */
3185
- public setLocalShareTrack(localShareTrack: MediaStreamTrack) {
3186
- let settings = null;
3193
+ public setLocalShareTrack(rawLocalShareTrack: MediaStreamTrack | null) {
3194
+ if (rawLocalShareTrack) {
3195
+ const settings = rawLocalShareTrack.getSettings();
3196
+
3197
+ const localDisplayTrack = new LocalDisplayTrack(
3198
+ MediaUtil.createMediaStream([rawLocalShareTrack])
3199
+ );
3187
3200
 
3188
- if (localShareTrack) {
3189
- this.mediaProperties.setLocalShareTrack(localShareTrack);
3201
+ this.mediaProperties.setLocalShareTrack(localDisplayTrack);
3190
3202
 
3191
- settings = localShareTrack.getSettings();
3192
3203
  this.mediaProperties.setMediaSettings('screen', {
3193
3204
  aspectRatio: settings.aspectRatio,
3194
3205
  frameRate: settings.frameRate,
3195
3206
  height: settings.height,
3196
3207
  width: settings.width,
3208
+ // @ts-ignore
3197
3209
  displaySurface: settings.displaySurface,
3210
+ // @ts-ignore
3198
3211
  cursor: settings.cursor,
3199
3212
  });
3200
3213
  LoggerProxy.logger.log(
@@ -3202,7 +3215,7 @@ export default class Meeting extends StatelessWebexPlugin {
3202
3215
  JSON.stringify(this.mediaProperties.mediaSettings.screen)
3203
3216
  );
3204
3217
 
3205
- localShareTrack.addEventListener('ended', this.handleShareTrackEnded);
3218
+ localDisplayTrack.on(LocalTrackEvents.Ended, this.handleShareTrackEnded);
3206
3219
 
3207
3220
  Trigger.trigger(
3208
3221
  this,
@@ -3213,11 +3226,12 @@ export default class Meeting extends StatelessWebexPlugin {
3213
3226
  EVENT_TRIGGERS.MEDIA_READY,
3214
3227
  {
3215
3228
  type: EVENT_TYPES.LOCAL_SHARE,
3216
- track: localShareTrack,
3229
+ track: rawLocalShareTrack,
3217
3230
  }
3218
3231
  );
3219
3232
  } else if (this.mediaProperties.shareTrack) {
3220
- this.mediaProperties.shareTrack.removeEventListener('ended', this.handleShareTrackEnded);
3233
+ this.mediaProperties.shareTrack.off(LocalTrackEvents.Ended, this.handleShareTrackEnded);
3234
+ this.mediaProperties.shareTrack.stop(); // todo: this line should be removed once SPARK-399694 are SPARK-399695 are done
3221
3235
  this.mediaProperties.setLocalShareTrack(null);
3222
3236
  }
3223
3237
  }
@@ -3235,11 +3249,7 @@ export default class Meeting extends StatelessWebexPlugin {
3235
3249
  return Media.stopTracks(audioTrack)
3236
3250
  .then(() => Media.stopTracks(videoTrack))
3237
3251
  .then(() => {
3238
- const audioStopped = audioTrack && audioTrack.readyState === ENDED;
3239
- const videoStopped = videoTrack && videoTrack.readyState === ENDED;
3240
-
3241
- // triggers event for audio and video stop , sometime either audio or video one of them exists
3242
- if (audioStopped || videoStopped) {
3252
+ if (audioTrack || videoTrack) {
3243
3253
  Trigger.trigger(
3244
3254
  this,
3245
3255
  {
@@ -3251,10 +3261,6 @@ export default class Meeting extends StatelessWebexPlugin {
3251
3261
  type: EVENT_TYPES.LOCAL,
3252
3262
  }
3253
3263
  );
3254
- } else if (audioTrack || videoTrack) {
3255
- LoggerProxy.logger.warn(
3256
- 'Meeting:index#closeLocalStream --> Warning: track might already been ended or unavaliable.'
3257
- );
3258
3264
  }
3259
3265
  });
3260
3266
  }
@@ -3270,7 +3276,7 @@ export default class Meeting extends StatelessWebexPlugin {
3270
3276
  const track = this.mediaProperties.shareTrack;
3271
3277
 
3272
3278
  return Media.stopTracks(track).then(() => {
3273
- if (track && track.readyState === ENDED) {
3279
+ if (track) {
3274
3280
  Trigger.trigger(
3275
3281
  this,
3276
3282
  {
@@ -3282,11 +3288,6 @@ export default class Meeting extends StatelessWebexPlugin {
3282
3288
  type: EVENT_TYPES.LOCAL_SHARE,
3283
3289
  }
3284
3290
  );
3285
- } else if (track) {
3286
- // Track exists but with wrong readyState
3287
- LoggerProxy.logger.warn(
3288
- `Meeting:index#closeLocalShare --> Error: MediaStreamTrack.readyState is ${track.readyState} for localShare`
3289
- );
3290
3291
  }
3291
3292
  });
3292
3293
  }
@@ -5100,6 +5101,12 @@ export default class Meeting extends StatelessWebexPlugin {
5100
5101
  return `MC-${this.id.substring(0, 4)}`;
5101
5102
  }
5102
5103
 
5104
+ /**
5105
+ * Creates a webrtc media connection
5106
+ *
5107
+ * @param {Object} turnServerInfo TURN server information
5108
+ * @returns {RoapMediaConnection | MultistreamRoapMediaConnection}
5109
+ */
5103
5110
  createMediaConnection(turnServerInfo) {
5104
5111
  const mc = Media.createMediaConnection(this.isMultistream, this.getMediaConnectionDebugId(), {
5105
5112
  mediaProperties: this.mediaProperties,
@@ -5297,7 +5304,9 @@ export default class Meeting extends StatelessWebexPlugin {
5297
5304
  )
5298
5305
  .then(() =>
5299
5306
  this.mediaProperties.waitForMediaConnectionConnected().catch(() => {
5300
- throw createMeetingsError(30202, 'Meeting connection failed');
5307
+ throw new Error(
5308
+ `Timed out waiting for media connection to be connected, correlationId=${this.correlationId}`
5309
+ );
5301
5310
  })
5302
5311
  )
5303
5312
  .then(() => {
@@ -5497,6 +5506,11 @@ export default class Meeting extends StatelessWebexPlugin {
5497
5506
  ) {
5498
5507
  const LOG_HEADER = 'Meeting:index#updateMedia -->';
5499
5508
 
5509
+ if (this.isMultistream) {
5510
+ throw new Error(
5511
+ 'updateMedia() is not supported with multistream, use publishTracks/unpublishTracks instead'
5512
+ );
5513
+ }
5500
5514
  if (!this.canUpdateMedia()) {
5501
5515
  return this.enqueueMediaUpdate(MEDIA_UPDATE_TYPE.ALL, options);
5502
5516
  }
@@ -5515,13 +5529,13 @@ export default class Meeting extends StatelessWebexPlugin {
5515
5529
  .updateSendReceiveOptions({
5516
5530
  send: {
5517
5531
  audio: this.mediaProperties.mediaDirection.sendAudio
5518
- ? this.mediaProperties.audioTrack
5532
+ ? this.mediaProperties.audioTrack.underlyingTrack
5519
5533
  : null,
5520
5534
  video: this.mediaProperties.mediaDirection.sendVideo
5521
- ? this.mediaProperties.videoTrack
5535
+ ? this.mediaProperties.videoTrack.underlyingTrack
5522
5536
  : null,
5523
5537
  screenShareVideo: this.mediaProperties.mediaDirection.sendShare
5524
- ? this.mediaProperties.shareTrack
5538
+ ? this.mediaProperties.shareTrack.underlyingTrack
5525
5539
  : null,
5526
5540
  },
5527
5541
  receive: {
@@ -5593,11 +5607,16 @@ export default class Meeting extends StatelessWebexPlugin {
5593
5607
  receiveAudio: boolean;
5594
5608
  stream: MediaStream;
5595
5609
  }) {
5610
+ if (this.isMultistream) {
5611
+ throw new Error(
5612
+ 'updateAudio() is not supported with multistream, use publishTracks/unpublishTracks instead'
5613
+ );
5614
+ }
5596
5615
  if (!this.canUpdateMedia()) {
5597
5616
  return this.enqueueMediaUpdate(MEDIA_UPDATE_TYPE.AUDIO, options);
5598
5617
  }
5599
5618
  const {sendAudio, receiveAudio, stream} = options;
5600
- let track = MeetingUtil.getTrack(stream).audioTrack;
5619
+ const track = MeetingUtil.getTrack(stream).audioTrack;
5601
5620
 
5602
5621
  if (typeof sendAudio !== 'boolean' || typeof receiveAudio !== 'boolean') {
5603
5622
  return Promise.reject(new ParameterError('Pass sendAudio and receiveAudio parameter'));
@@ -5607,20 +5626,6 @@ export default class Meeting extends StatelessWebexPlugin {
5607
5626
  return Promise.reject(new Error('media connection not established, call addMedia() first'));
5608
5627
  }
5609
5628
 
5610
- if (this.effects && this.effects.state) {
5611
- const bnrEnabled = this.effects.state.bnr.enabled;
5612
-
5613
- if (
5614
- sendAudio &&
5615
- !this.isAudioMuted() &&
5616
- (bnrEnabled === BNR_STATUS.ENABLED || bnrEnabled === BNR_STATUS.SHOULD_ENABLE)
5617
- ) {
5618
- LoggerProxy.logger.info('Meeting:index#updateAudio. Calling WebRTC enable bnr method');
5619
- track = await this.internal_enableBNR(track);
5620
- LoggerProxy.logger.info('Meeting:index#updateAudio. WebRTC enable bnr request completed');
5621
- }
5622
- }
5623
-
5624
5629
  return MeetingUtil.validateOptions({sendAudio, localStream: stream})
5625
5630
  .then(() =>
5626
5631
  this.mediaProperties.webrtcMediaConnection.updateSendReceiveOptions({
@@ -5659,6 +5664,11 @@ export default class Meeting extends StatelessWebexPlugin {
5659
5664
  * @memberof Meeting
5660
5665
  */
5661
5666
  public updateVideo(options: {sendVideo: boolean; receiveVideo: boolean; stream: MediaStream}) {
5667
+ if (this.isMultistream) {
5668
+ throw new Error(
5669
+ 'updateVideo() is not supported with multistream, use publishTracks/unpublishTracks instead'
5670
+ );
5671
+ }
5662
5672
  if (!this.canUpdateMedia()) {
5663
5673
  return this.enqueueMediaUpdate(MEDIA_UPDATE_TYPE.VIDEO, options);
5664
5674
  }
@@ -5736,6 +5746,11 @@ export default class Meeting extends StatelessWebexPlugin {
5736
5746
  stream?: any;
5737
5747
  skipSignalingCheck?: boolean;
5738
5748
  }) {
5749
+ if (this.isMultistream) {
5750
+ throw new Error(
5751
+ 'updateShare() is not supported with multistream, use publishTracks/unpublishTracks instead'
5752
+ );
5753
+ }
5739
5754
  if (!options.skipSignalingCheck && !this.canUpdateMedia()) {
5740
5755
  return this.enqueueMediaUpdate(MEDIA_UPDATE_TYPE.SHARE, options);
5741
5756
  }
@@ -5809,6 +5824,11 @@ export default class Meeting extends StatelessWebexPlugin {
5809
5824
  this.video = this.video || createMuteState(VIDEO, this, this.mediaProperties.mediaDirection);
5810
5825
  // Validation is already done in addMedia so no need to check if the lenght is greater then 0
5811
5826
  this.setLocalTracks(localStream);
5827
+ if (this.isMultistream && localShare) {
5828
+ throw new Error(
5829
+ 'calling addMedia() with localShare stream is not supported when using multistream'
5830
+ );
5831
+ }
5812
5832
  this.setLocalShareTrack(MeetingUtil.getTrack(localShare).videoTrack);
5813
5833
  }
5814
5834
 
@@ -6114,7 +6134,6 @@ export default class Meeting extends StatelessWebexPlugin {
6114
6134
 
6115
6135
  if (content && this.mediaProperties.mediaDirection.sendShare) {
6116
6136
  Metrics.postEvent({event: eventType.SHARE_STOPPED, meeting: this});
6117
- Media.stopTracks(this.mediaProperties.shareTrack);
6118
6137
 
6119
6138
  if (content.floor.beneficiary.id !== this.selfId) {
6120
6139
  // remote participant started sharing and caused our sharing to stop, we don't want to send any floor action request in that case
@@ -6690,14 +6709,16 @@ export default class Meeting extends StatelessWebexPlugin {
6690
6709
 
6691
6710
  /**
6692
6711
  * Handle logging the media
6693
- * @param {Object} audioTrack The audio track
6694
- * @param {Object} videoTrack The video track
6712
+ * @param {Object} mediaProperties
6695
6713
  * @private
6696
6714
  * @returns {undefined}
6697
6715
  */
6698
- private handleMediaLogging({audioTrack, videoTrack}: any) {
6699
- MeetingUtil.handleVideoLogging(videoTrack);
6700
- MeetingUtil.handleAudioLogging(audioTrack);
6716
+ private handleMediaLogging(mediaProperties: {
6717
+ audioTrack: LocalMicrophoneTrack | null;
6718
+ videoTrack: LocalCameraTrack | null;
6719
+ }) {
6720
+ MeetingUtil.handleVideoLogging(mediaProperties.videoTrack);
6721
+ MeetingUtil.handleAudioLogging(mediaProperties.audioTrack);
6701
6722
  }
6702
6723
 
6703
6724
  /**
@@ -6960,121 +6981,6 @@ export default class Meeting extends StatelessWebexPlugin {
6960
6981
  }
6961
6982
  };
6962
6983
 
6963
- /**
6964
- * Internal API to return status of BNR
6965
- * @returns {Boolean}
6966
- * @public
6967
- * @memberof Meeting
6968
- */
6969
- public isBnrEnabled() {
6970
- return this.effects && this.effects.isBnrEnabled();
6971
- }
6972
-
6973
- /**
6974
- * Internal API to obtain BNR enabled MediaStream
6975
- * @returns {Promise<MediaStreamTrack>}
6976
- * @private
6977
- * @param {MedaiStreamTrack} audioTrack from updateAudio
6978
- * @memberof Meeting
6979
- */
6980
- private async internal_enableBNR(audioTrack: any) {
6981
- try {
6982
- LoggerProxy.logger.info('Meeting:index#internal_enableBNR. Internal enable BNR called');
6983
- const bnrAudioTrack = await WebRTCMedia.Effects.BNR.enableBNR(audioTrack);
6984
-
6985
- LoggerProxy.logger.info(
6986
- 'Meeting:index#internal_enableBNR. BNR enabled track obtained from WebRTC & returned as stream'
6987
- );
6988
-
6989
- return bnrAudioTrack;
6990
- } catch (error) {
6991
- LoggerProxy.logger.error('Meeting:index#internal_enableBNR.', error);
6992
- throw error;
6993
- }
6994
- }
6995
-
6996
- /**
6997
- * Enable the audio track with BNR for a meeting
6998
- * @returns {Promise} resolves the data from enable bnr or rejects if there is no audio or audio is muted
6999
- * @public
7000
- * @memberof Meeting
7001
- */
7002
- public enableBNR() {
7003
- if (
7004
- typeof this.mediaProperties === 'undefined' ||
7005
- typeof this.mediaProperties.audioTrack === 'undefined'
7006
- ) {
7007
- return Promise.reject(new Error("Meeting doesn't have an audioTrack attached"));
7008
- }
7009
-
7010
- if (this.isAudioMuted()) {
7011
- return Promise.reject(new Error('Cannot enable BNR while meeting is muted'));
7012
- }
7013
-
7014
- this.effects = this.effects || createEffectsState('BNR');
7015
-
7016
- const LOG_HEADER = 'Meeting:index#enableBNR -->';
7017
-
7018
- return logRequest(
7019
- this.effects
7020
- .handleClientRequest(true, this)
7021
- .then((res) => {
7022
- LoggerProxy.logger.info('Meeting:index#enableBNR. Enable bnr completed');
7023
-
7024
- return res;
7025
- })
7026
- .catch((error) => {
7027
- throw error;
7028
- }),
7029
- {
7030
- header: `${LOG_HEADER} enable bnr`,
7031
- success: `${LOG_HEADER} enable bnr success`,
7032
- failure: `${LOG_HEADER} enable bnr failure, `,
7033
- }
7034
- );
7035
- }
7036
-
7037
- /**
7038
- * Disable the BNR for an audio track
7039
- * @returns {Promise} resolves the data from disable bnr or rejects if there is no audio set
7040
- * @public
7041
- * @memberof Meeting
7042
- */
7043
- public disableBNR() {
7044
- if (
7045
- typeof this.mediaProperties === 'undefined' ||
7046
- typeof this.mediaProperties.audioTrack === 'undefined'
7047
- ) {
7048
- return Promise.reject(new Error("Meeting doesn't have an audioTrack attached"));
7049
- }
7050
-
7051
- if (!this.isBnrEnabled()) {
7052
- return Promise.reject(new Error('Can not disable as BNR is not enabled'));
7053
- }
7054
-
7055
- this.effects = this.effects || createEffectsState('BNR');
7056
-
7057
- const LOG_HEADER = 'Meeting:index#disableBNR -->';
7058
-
7059
- return logRequest(
7060
- this.effects
7061
- .handleClientRequest(false, this)
7062
- .then((res) => {
7063
- LoggerProxy.logger.info('Meeting:index#disableBNR. Disable bnr completed');
7064
-
7065
- return res;
7066
- })
7067
- .catch((error) => {
7068
- throw error;
7069
- }),
7070
- {
7071
- header: `${LOG_HEADER} disable bnr`,
7072
- success: `${LOG_HEADER} disable bnr success`,
7073
- failure: `${LOG_HEADER} disable bnr failure, `,
7074
- }
7075
- );
7076
- }
7077
-
7078
6984
  /**
7079
6985
  * starts keepAlives being sent
7080
6986
  * @returns {void}
@@ -7226,8 +7132,7 @@ export default class Meeting extends StatelessWebexPlugin {
7226
7132
  this.mediaProperties.mediaDirection.sendShare = true;
7227
7133
 
7228
7134
  await this.mediaProperties.webrtcMediaConnection.publishTrack(
7229
- tracks.screenShare.video,
7230
- 'slides'
7135
+ this.mediaProperties.shareTrack
7231
7136
  );
7232
7137
  }
7233
7138
 
@@ -7238,7 +7143,9 @@ export default class Meeting extends StatelessWebexPlugin {
7238
7143
  // audio mute state could be undefined if you have not sent audio before
7239
7144
  this.audio = this.audio || createMuteState(AUDIO, this, this.mediaProperties.mediaDirection);
7240
7145
 
7241
- await this.mediaProperties.webrtcMediaConnection.publishTrack(tracks.microphone, 'main');
7146
+ await this.mediaProperties.webrtcMediaConnection.publishTrack(
7147
+ this.mediaProperties.audioTrack
7148
+ );
7242
7149
  }
7243
7150
 
7244
7151
  if (tracks.camera) {
@@ -7248,7 +7155,9 @@ export default class Meeting extends StatelessWebexPlugin {
7248
7155
  // video state could be undefined if you have not sent video before
7249
7156
  this.video = this.video || createMuteState(VIDEO, this, this.mediaProperties.mediaDirection);
7250
7157
 
7251
- await this.mediaProperties.webrtcMediaConnection.publishTrack(tracks.camera, 'main');
7158
+ await this.mediaProperties.webrtcMediaConnection.publishTrack(
7159
+ this.mediaProperties.videoTrack
7160
+ );
7252
7161
  }
7253
7162
  }
7254
7163
 
@@ -7264,32 +7173,41 @@ export default class Meeting extends StatelessWebexPlugin {
7264
7173
  const unpublishPromises = [];
7265
7174
 
7266
7175
  for (const track of tracks) {
7267
- if (track === this.mediaProperties.shareTrack) {
7176
+ // @ts-ignore originalTrack is private - this will be fixed in SPARK-399694
7177
+ if (track === this.mediaProperties.shareTrack?.originalTrack) {
7178
+ const localTrackToUnpublish = this.mediaProperties.shareTrack;
7179
+
7268
7180
  this.setLocalShareTrack(null);
7269
7181
 
7270
7182
  this.releaseScreenShareFloor(); // we ignore the returned promise here on purpose
7271
7183
  this.mediaProperties.mediaDirection.sendShare = false;
7272
7184
 
7273
7185
  unpublishPromises.push(
7274
- this.mediaProperties.webrtcMediaConnection.unpublishTrack(track, 'slides')
7186
+ this.mediaProperties.webrtcMediaConnection.unpublishTrack(localTrackToUnpublish)
7275
7187
  );
7276
7188
  }
7277
7189
 
7278
- if (track === this.mediaProperties.audioTrack) {
7190
+ // @ts-ignore originalTrack is private - this will be fixed in SPARK-399694
7191
+ if (track === this.mediaProperties.audioTrack?.originalTrack) {
7192
+ const localTrackToUnpublish = this.mediaProperties.audioTrack;
7193
+
7279
7194
  this.setLocalAudioTrack(null);
7280
7195
  this.mediaProperties.mediaDirection.sendAudio = false;
7281
7196
 
7282
7197
  unpublishPromises.push(
7283
- this.mediaProperties.webrtcMediaConnection.unpublishTrack(track, 'main')
7198
+ this.mediaProperties.webrtcMediaConnection.unpublishTrack(localTrackToUnpublish)
7284
7199
  );
7285
7200
  }
7286
7201
 
7287
- if (track === this.mediaProperties.videoTrack) {
7202
+ // @ts-ignore originalTrack is private - this will be fixed in SPARK-399694
7203
+ if (track === this.mediaProperties.videoTrack?.originalTrack) {
7204
+ const localTrackToUnpublish = this.mediaProperties.videoTrack;
7205
+
7288
7206
  this.setLocalVideoTrack(null);
7289
7207
  this.mediaProperties.mediaDirection.sendVideo = false;
7290
7208
 
7291
7209
  unpublishPromises.push(
7292
- this.mediaProperties.webrtcMediaConnection.unpublishTrack(track, 'main')
7210
+ this.mediaProperties.webrtcMediaConnection.unpublishTrack(localTrackToUnpublish)
7293
7211
  );
7294
7212
  }
7295
7213
  }
@@ -1,7 +1,6 @@
1
1
  import LoggerProxy from '../common/logs/logger-proxy';
2
2
  import ParameterError from '../common/errors/parameter';
3
3
  import PermissionError from '../common/errors/permission';
4
- import Media from '../media';
5
4
  import MeetingUtil from './util';
6
5
  import {AUDIO, VIDEO} from '../constants';
7
6
 
@@ -114,10 +113,11 @@ class MuteState {
114
113
  * @returns {void}
115
114
  */
116
115
  public applyClientStateLocally(meeting?: any) {
117
- Media.setLocalTrack(
118
- !this.state.client.localMute,
119
- this.type === AUDIO ? meeting.mediaProperties.audioTrack : meeting.mediaProperties.videoTrack
120
- );
116
+ if (this.type === AUDIO) {
117
+ meeting.mediaProperties.audioTrack?.setMuted(this.state.client.localMute);
118
+ } else {
119
+ meeting.mediaProperties.videoTrack?.setMuted(this.state.client.localMute);
120
+ }
121
121
  }
122
122
 
123
123
  /**