@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.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/edit-lock-error.js +52 -0
- package/dist/breakouts/edit-lock-error.js.map +1 -0
- package/dist/breakouts/index.js +86 -2
- package/dist/breakouts/index.js.map +1 -1
- package/dist/constants.js +12 -1
- package/dist/constants.js.map +1 -1
- package/dist/media/index.js +4 -18
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +3 -3
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/index.js +194 -306
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.js +7 -2
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/util.js +2 -2
- package/dist/meeting/util.js.map +1 -1
- package/dist/metrics/constants.js +0 -4
- package/dist/metrics/constants.js.map +1 -1
- package/dist/reconnection-manager/index.js +1 -2
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/statsAnalyzer/index.js +8 -4
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/types/breakouts/edit-lock-error.d.ts +15 -0
- package/dist/types/constants.d.ts +11 -0
- package/dist/types/media/properties.d.ts +7 -6
- package/dist/types/meeting/index.d.ts +11 -36
- package/dist/types/metrics/constants.d.ts +0 -4
- package/package.json +19 -19
- package/src/breakouts/README.md +8 -2
- package/src/breakouts/edit-lock-error.ts +25 -0
- package/src/breakouts/index.ts +73 -0
- package/src/constants.ts +11 -0
- package/src/media/index.ts +14 -24
- package/src/media/properties.ts +16 -10
- package/src/meeting/index.ts +122 -204
- package/src/meeting/muteState.ts +5 -5
- package/src/meeting/util.ts +5 -4
- package/src/metrics/constants.ts +0 -4
- package/src/reconnection-manager/index.ts +1 -1
- package/src/statsAnalyzer/index.ts +4 -4
- package/test/integration/spec/converged-space-meetings.js +3 -3
- package/test/integration/spec/journey.js +3 -3
- package/test/unit/spec/breakouts/edit-lock-error.ts +30 -0
- package/test/unit/spec/breakouts/index.ts +92 -1
- package/test/unit/spec/media/index.ts +8 -6
- package/test/unit/spec/meeting/index.js +87 -114
- package/test/unit/spec/meeting/muteState.js +21 -22
- package/test/unit/spec/meeting/utils.js +3 -1
- package/test/utils/testUtils.js +30 -25
- package/dist/meeting/effectsState.js +0 -262
- package/dist/meeting/effectsState.js.map +0 -1
- package/dist/types/meeting/effectsState.d.ts +0 -42
- package/src/meeting/effectsState.ts +0 -211
- package/test/unit/spec/meeting/effectsState.js +0 -285
package/src/meeting/index.ts
CHANGED
|
@@ -7,7 +7,10 @@ import {
|
|
|
7
7
|
Errors,
|
|
8
8
|
ErrorType,
|
|
9
9
|
Event,
|
|
10
|
-
|
|
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
|
-
|
|
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([
|
|
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
|
-
|
|
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.
|
|
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: '
|
|
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}
|
|
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(
|
|
3089
|
-
if (
|
|
3090
|
-
const settings =
|
|
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(
|
|
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}
|
|
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(
|
|
3121
|
-
if (
|
|
3122
|
-
const {aspectRatio, frameRate, height, width, deviceId} =
|
|
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(
|
|
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}
|
|
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(
|
|
3186
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
3229
|
+
track: rawLocalShareTrack,
|
|
3217
3230
|
}
|
|
3218
3231
|
);
|
|
3219
3232
|
} else if (this.mediaProperties.shareTrack) {
|
|
3220
|
-
this.mediaProperties.shareTrack.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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}
|
|
6694
|
-
* @param {Object} videoTrack The video track
|
|
6712
|
+
* @param {Object} mediaProperties
|
|
6695
6713
|
* @private
|
|
6696
6714
|
* @returns {undefined}
|
|
6697
6715
|
*/
|
|
6698
|
-
private handleMediaLogging(
|
|
6699
|
-
|
|
6700
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
7186
|
+
this.mediaProperties.webrtcMediaConnection.unpublishTrack(localTrackToUnpublish)
|
|
7275
7187
|
);
|
|
7276
7188
|
}
|
|
7277
7189
|
|
|
7278
|
-
|
|
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(
|
|
7198
|
+
this.mediaProperties.webrtcMediaConnection.unpublishTrack(localTrackToUnpublish)
|
|
7284
7199
|
);
|
|
7285
7200
|
}
|
|
7286
7201
|
|
|
7287
|
-
|
|
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(
|
|
7210
|
+
this.mediaProperties.webrtcMediaConnection.unpublishTrack(localTrackToUnpublish)
|
|
7293
7211
|
);
|
|
7294
7212
|
}
|
|
7295
7213
|
}
|
package/src/meeting/muteState.ts
CHANGED
|
@@ -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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
/**
|