@webex/plugin-meetings 3.0.0-beta.391 → 3.0.0-beta.392
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/index.js +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +16 -7
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/meeting/index.js +738 -616
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/util.js +4 -1
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting/voicea-meeting.js +172 -0
- package/dist/meeting/voicea-meeting.js.map +1 -0
- package/dist/meeting-info/meeting-info-v2.js +9 -6
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/util.js +7 -6
- package/dist/meeting-info/util.js.map +1 -1
- package/dist/meeting-info/utilv2.js +8 -4
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/member/index.js +0 -1
- package/dist/member/index.js.map +1 -1
- package/dist/types/constants.d.ts +8 -2
- package/dist/types/meeting/index.d.ts +56 -12
- package/dist/types/meeting/voicea-meeting.d.ts +16 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +20 -20
- package/src/config.ts +2 -4
- package/src/constants.ts +11 -2
- package/src/meeting/index.ts +320 -157
- package/src/meeting/util.ts +5 -1
- package/src/meeting/voicea-meeting.ts +122 -0
- package/src/meeting-info/meeting-info-v2.ts +5 -11
- package/src/meeting-info/util.ts +12 -9
- package/src/meeting-info/utilv2.ts +24 -14
- package/src/member/index.ts +0 -1
- package/test/integration/spec/journey.js +2 -2
- package/test/unit/spec/breakouts/breakout.ts +2 -1
- package/test/unit/spec/breakouts/index.ts +7 -4
- package/test/unit/spec/locus-info/index.js +27 -18
- package/test/unit/spec/locus-info/selfUtils.js +6 -11
- package/test/unit/spec/media/index.ts +5 -0
- package/test/unit/spec/meeting/index.js +315 -87
- package/test/unit/spec/meeting/utils.js +52 -10
- package/test/unit/spec/meeting/voicea-meeting.ts +266 -0
- package/test/unit/spec/meeting-info/meetinginfov2.js +20 -15
- package/test/unit/spec/meetings/index.js +78 -10
- package/test/unit/spec/metrics/index.js +1 -2
- package/test/unit/spec/multistream/mediaRequestManager.ts +1 -0
- package/test/unit/spec/recording-controller/index.js +0 -1
- package/test/unit/spec/roap/turnDiscovery.ts +1 -1
package/src/meeting/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import uuid from 'uuid';
|
|
2
2
|
import {cloneDeep, isEqual, isEmpty} from 'lodash';
|
|
3
|
-
import
|
|
3
|
+
import jwtDecode from 'jwt-decode';
|
|
4
4
|
// @ts-ignore - Fix this
|
|
5
5
|
import {StatelessWebexPlugin} from '@webex/webex-core';
|
|
6
6
|
// @ts-ignore - Types not available for @webex/common
|
|
@@ -33,6 +33,12 @@ import {
|
|
|
33
33
|
RemoteStream,
|
|
34
34
|
} from '@webex/media-helpers';
|
|
35
35
|
|
|
36
|
+
import {
|
|
37
|
+
EVENT_TRIGGERS as VOICEAEVENTS,
|
|
38
|
+
TURN_ON_CAPTION_STATUS,
|
|
39
|
+
} from '@webex/internal-plugin-voicea';
|
|
40
|
+
import {processNewCaptions} from './voicea-meeting';
|
|
41
|
+
|
|
36
42
|
import {
|
|
37
43
|
MeetingNotActiveError,
|
|
38
44
|
UserInLobbyError,
|
|
@@ -40,6 +46,7 @@ import {
|
|
|
40
46
|
UserNotJoinedError,
|
|
41
47
|
AddMediaFailed,
|
|
42
48
|
} from '../common/errors/webex-errors';
|
|
49
|
+
|
|
43
50
|
import {StatsAnalyzer, EVENTS as StatsAnalyzerEvents} from '../statsAnalyzer';
|
|
44
51
|
import NetworkQualityMonitor from '../networkQualityMonitor';
|
|
45
52
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
@@ -59,7 +66,6 @@ import MeetingsUtil from '../meetings/util';
|
|
|
59
66
|
import RecordingUtil from '../recording-controller/util';
|
|
60
67
|
import ControlsOptionsUtil from '../controls-options-manager/util';
|
|
61
68
|
import MediaUtil from '../media/util';
|
|
62
|
-
import Transcription from '../transcription';
|
|
63
69
|
import {Reactions, SkinTones} from '../reactions/reactions';
|
|
64
70
|
import PasswordError from '../common/errors/password-error';
|
|
65
71
|
import CaptchaError from '../common/errors/captcha-error';
|
|
@@ -97,7 +103,6 @@ import {
|
|
|
97
103
|
SHARE_STATUS,
|
|
98
104
|
SHARE_STOPPED_REASON,
|
|
99
105
|
VIDEO,
|
|
100
|
-
HTTP_VERBS,
|
|
101
106
|
SELF_ROLES,
|
|
102
107
|
INTERPRETATION,
|
|
103
108
|
SELF_POLICY,
|
|
@@ -114,7 +119,6 @@ import {
|
|
|
114
119
|
MeetingInfoV2CaptchaError,
|
|
115
120
|
MeetingInfoV2PolicyError,
|
|
116
121
|
} from '../meeting-info/meeting-info-v2';
|
|
117
|
-
import BrowserDetection from '../common/browser-detection';
|
|
118
122
|
import {CSI, ReceiveSlotManager} from '../multistream/receiveSlotManager';
|
|
119
123
|
import SendSlotManager from '../multistream/sendSlotManager';
|
|
120
124
|
import {MediaRequestManager} from '../multistream/mediaRequestManager';
|
|
@@ -142,8 +146,6 @@ import ControlsOptionsManager from '../controls-options-manager';
|
|
|
142
146
|
import PermissionError from '../common/errors/permission';
|
|
143
147
|
import {LocusMediaRequest} from './locusMediaRequest';
|
|
144
148
|
|
|
145
|
-
const {isBrowser} = BrowserDetection();
|
|
146
|
-
|
|
147
149
|
const logRequest = (request: any, {logText = ''}) => {
|
|
148
150
|
LoggerProxy.logger.info(`${logText} - sending request`);
|
|
149
151
|
|
|
@@ -159,6 +161,36 @@ const logRequest = (request: any, {logText = ''}) => {
|
|
|
159
161
|
});
|
|
160
162
|
};
|
|
161
163
|
|
|
164
|
+
export type CaptionData = {
|
|
165
|
+
id: string;
|
|
166
|
+
isFinal: boolean;
|
|
167
|
+
translations: Array<string>;
|
|
168
|
+
text: string;
|
|
169
|
+
currentCaptionLanguage: string;
|
|
170
|
+
timestamp: string;
|
|
171
|
+
speaker: string;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
export type Transcription = {
|
|
175
|
+
languageOptions: {
|
|
176
|
+
captionLanguages?: string; // list of supported caption languages from backend
|
|
177
|
+
maxLanguages?: number;
|
|
178
|
+
spokenLanguages?: Array<string>; // list of supported spoken languages from backend
|
|
179
|
+
currentCaptionLanguage?: string; // current caption language - default is english
|
|
180
|
+
requestedCaptionLanguage?: string; // requested caption language
|
|
181
|
+
currentSpokenLanguage?: string; // current spoken language - default is english
|
|
182
|
+
};
|
|
183
|
+
status: string;
|
|
184
|
+
isListening: boolean;
|
|
185
|
+
commandText: string;
|
|
186
|
+
captions: Array<CaptionData>;
|
|
187
|
+
showCaptionBox: boolean;
|
|
188
|
+
transcribingRequestStatus: string;
|
|
189
|
+
isCaptioning: boolean;
|
|
190
|
+
speakerProxy: Map<string, any>;
|
|
191
|
+
interimCaptions: Map<string, CaptionData>;
|
|
192
|
+
};
|
|
193
|
+
|
|
162
194
|
export type LocalStreams = {
|
|
163
195
|
microphone?: LocalMicrophoneStream;
|
|
164
196
|
camera?: LocalCameraStream;
|
|
@@ -590,6 +622,46 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
590
622
|
remoteShareInstanceId: string;
|
|
591
623
|
turnDiscoverySkippedReason: string;
|
|
592
624
|
turnServerUsed: boolean;
|
|
625
|
+
areVoiceaEventsSetup = false;
|
|
626
|
+
voiceaListenerCallbacks: object = {
|
|
627
|
+
[VOICEAEVENTS.VOICEA_ANNOUNCEMENT]: (payload: Transcription['languageOptions']) => {
|
|
628
|
+
this.transcription.languageOptions = payload;
|
|
629
|
+
Trigger.trigger(
|
|
630
|
+
this,
|
|
631
|
+
{
|
|
632
|
+
file: 'meeting/index',
|
|
633
|
+
function: 'setUpVoiceaListeners',
|
|
634
|
+
},
|
|
635
|
+
EVENT_TRIGGERS.MEETING_STARTED_RECEIVING_TRANSCRIPTION,
|
|
636
|
+
payload
|
|
637
|
+
);
|
|
638
|
+
},
|
|
639
|
+
[VOICEAEVENTS.CAPTIONS_TURNED_ON]: () => {
|
|
640
|
+
this.transcription.status = TURN_ON_CAPTION_STATUS.ENABLED;
|
|
641
|
+
},
|
|
642
|
+
[VOICEAEVENTS.EVA_COMMAND]: (payload) => {
|
|
643
|
+
const {data} = payload;
|
|
644
|
+
|
|
645
|
+
this.transcription.isListening = !!data.isListening;
|
|
646
|
+
this.transcription.commandText = data.text ?? '';
|
|
647
|
+
},
|
|
648
|
+
[VOICEAEVENTS.NEW_CAPTION]: (data) => {
|
|
649
|
+
processNewCaptions({data, meeting: this});
|
|
650
|
+
Trigger.trigger(
|
|
651
|
+
this,
|
|
652
|
+
{
|
|
653
|
+
file: 'meeting/index',
|
|
654
|
+
function: 'setUpVoiceaListeners',
|
|
655
|
+
},
|
|
656
|
+
EVENT_TRIGGERS.MEETING_CAPTION_RECEIVED,
|
|
657
|
+
{
|
|
658
|
+
captions: this.transcription.captions,
|
|
659
|
+
interimCaptions: this.transcription.interimCaptions,
|
|
660
|
+
}
|
|
661
|
+
);
|
|
662
|
+
},
|
|
663
|
+
};
|
|
664
|
+
|
|
593
665
|
private retriedWithTurnServer: boolean;
|
|
594
666
|
private sendSlotManager: SendSlotManager = new SendSlotManager(LoggerProxy);
|
|
595
667
|
private deferSDPAnswer?: Defer; // used for waiting for a response
|
|
@@ -1188,7 +1260,17 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1188
1260
|
* @private
|
|
1189
1261
|
* @memberof Meeting
|
|
1190
1262
|
*/
|
|
1191
|
-
this.transcription =
|
|
1263
|
+
this.transcription = {
|
|
1264
|
+
captions: [],
|
|
1265
|
+
isListening: false,
|
|
1266
|
+
commandText: '',
|
|
1267
|
+
languageOptions: {},
|
|
1268
|
+
showCaptionBox: false,
|
|
1269
|
+
transcribingRequestStatus: 'INACTIVE',
|
|
1270
|
+
isCaptioning: false,
|
|
1271
|
+
interimCaptions: {} as Map<string, CaptionData>,
|
|
1272
|
+
speakerProxy: {} as Map<string, any>,
|
|
1273
|
+
} as Transcription;
|
|
1192
1274
|
|
|
1193
1275
|
/**
|
|
1194
1276
|
* Password status. If it's PASSWORD_STATUS.REQUIRED then verifyPassword() needs to be called
|
|
@@ -1904,6 +1986,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1904
1986
|
* @memberof Meeting
|
|
1905
1987
|
*/
|
|
1906
1988
|
private setUpInterpretationListener() {
|
|
1989
|
+
// TODO: check if its getting used or not
|
|
1907
1990
|
this.simultaneousInterpretation.on(INTERPRETATION.EVENTS.SUPPORT_LANGUAGES_UPDATE, () => {
|
|
1908
1991
|
Trigger.trigger(
|
|
1909
1992
|
this,
|
|
@@ -1914,7 +1997,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1914
1997
|
EVENT_TRIGGERS.MEETING_INTERPRETATION_SUPPORT_LANGUAGES_UPDATE
|
|
1915
1998
|
);
|
|
1916
1999
|
});
|
|
1917
|
-
|
|
2000
|
+
// TODO: check if its getting used or not
|
|
1918
2001
|
this.simultaneousInterpretation.on(
|
|
1919
2002
|
INTERPRETATION.EVENTS.HANDOFF_REQUESTS_ARRIVED,
|
|
1920
2003
|
(payload) => {
|
|
@@ -1931,6 +2014,43 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1931
2014
|
);
|
|
1932
2015
|
}
|
|
1933
2016
|
|
|
2017
|
+
/**
|
|
2018
|
+
* Set up the listeners for captions
|
|
2019
|
+
* @returns {undefined}
|
|
2020
|
+
* @private
|
|
2021
|
+
* @memberof Meeting
|
|
2022
|
+
*/
|
|
2023
|
+
private setUpVoiceaListeners() {
|
|
2024
|
+
// @ts-ignore
|
|
2025
|
+
this.webex.internal.voicea.listenToEvents();
|
|
2026
|
+
|
|
2027
|
+
// @ts-ignore
|
|
2028
|
+
this.webex.internal.voicea.on(
|
|
2029
|
+
VOICEAEVENTS.VOICEA_ANNOUNCEMENT,
|
|
2030
|
+
this.voiceaListenerCallbacks[VOICEAEVENTS.VOICEA_ANNOUNCEMENT]
|
|
2031
|
+
);
|
|
2032
|
+
|
|
2033
|
+
// @ts-ignore
|
|
2034
|
+
this.webex.internal.voicea.on(
|
|
2035
|
+
VOICEAEVENTS.CAPTIONS_TURNED_ON,
|
|
2036
|
+
this.voiceaListenerCallbacks[VOICEAEVENTS.CAPTIONS_TURNED_ON]
|
|
2037
|
+
);
|
|
2038
|
+
|
|
2039
|
+
// @ts-ignore
|
|
2040
|
+
this.webex.internal.voicea.on(
|
|
2041
|
+
VOICEAEVENTS.EVA_COMMAND,
|
|
2042
|
+
this.voiceaListenerCallbacks[VOICEAEVENTS.EVA_COMMAND]
|
|
2043
|
+
);
|
|
2044
|
+
|
|
2045
|
+
// @ts-ignore
|
|
2046
|
+
this.webex.internal.voicea.on(
|
|
2047
|
+
VOICEAEVENTS.NEW_CAPTION,
|
|
2048
|
+
this.voiceaListenerCallbacks[VOICEAEVENTS.NEW_CAPTION]
|
|
2049
|
+
);
|
|
2050
|
+
|
|
2051
|
+
this.areVoiceaEventsSetup = true;
|
|
2052
|
+
}
|
|
2053
|
+
|
|
1934
2054
|
/**
|
|
1935
2055
|
* Set up the locus info listener for meetings disconnected due to inactivity
|
|
1936
2056
|
* @returns {undefined}
|
|
@@ -2220,7 +2340,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2220
2340
|
modifiedBy,
|
|
2221
2341
|
lastModified,
|
|
2222
2342
|
};
|
|
2223
|
-
|
|
2224
2343
|
Trigger.trigger(
|
|
2225
2344
|
this,
|
|
2226
2345
|
{
|
|
@@ -2251,19 +2370,22 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2251
2370
|
this.locusInfo.on(
|
|
2252
2371
|
LOCUSINFO.EVENTS.CONTROLS_MEETING_TRANSCRIBE_UPDATED,
|
|
2253
2372
|
({caption, transcribing}) => {
|
|
2254
|
-
//
|
|
2255
|
-
if (
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2373
|
+
// user need to be joined to start the llm and receive transcription
|
|
2374
|
+
if (this.isJoined()) {
|
|
2375
|
+
// @ts-ignore - config coming from registerPlugin
|
|
2376
|
+
if (transcribing && !this.transcription) {
|
|
2377
|
+
this.startTranscription();
|
|
2378
|
+
} else if (!transcribing && this.transcription) {
|
|
2379
|
+
Trigger.trigger(
|
|
2380
|
+
this,
|
|
2381
|
+
{
|
|
2382
|
+
file: 'meeting/index',
|
|
2383
|
+
function: 'setupLocusControlsListener',
|
|
2384
|
+
},
|
|
2385
|
+
EVENT_TRIGGERS.MEETING_STOPPED_RECEIVING_TRANSCRIPTION,
|
|
2386
|
+
{caption, transcribing}
|
|
2387
|
+
);
|
|
2388
|
+
}
|
|
2267
2389
|
}
|
|
2268
2390
|
}
|
|
2269
2391
|
);
|
|
@@ -2925,7 +3047,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2925
3047
|
});
|
|
2926
3048
|
}
|
|
2927
3049
|
});
|
|
2928
|
-
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ADMITTED_GUEST, (payload) => {
|
|
3050
|
+
this.locusInfo.on(LOCUSINFO.EVENTS.SELF_ADMITTED_GUEST, async (payload) => {
|
|
2929
3051
|
this.stopKeepAlive();
|
|
2930
3052
|
|
|
2931
3053
|
if (payload) {
|
|
@@ -3619,7 +3741,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3619
3741
|
* @returns {void}
|
|
3620
3742
|
*/
|
|
3621
3743
|
public setPermissionTokenPayload(permissionToken: string) {
|
|
3622
|
-
this.permissionTokenPayload =
|
|
3744
|
+
this.permissionTokenPayload = jwtDecode(permissionToken);
|
|
3623
3745
|
this.permissionTokenReceivedLocalTime = new Date().getTime();
|
|
3624
3746
|
}
|
|
3625
3747
|
|
|
@@ -4489,7 +4611,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4489
4611
|
}
|
|
4490
4612
|
|
|
4491
4613
|
LoggerProxy.logger.error(
|
|
4492
|
-
'Meeting:index#isTranscriptionSupported --> Webex Assistant is not supported'
|
|
4614
|
+
'Meeting:index#isTranscriptionSupported --> Webex Assistant is not enabled/supported'
|
|
4493
4615
|
);
|
|
4494
4616
|
|
|
4495
4617
|
return false;
|
|
@@ -4510,109 +4632,139 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4510
4632
|
}
|
|
4511
4633
|
|
|
4512
4634
|
/**
|
|
4513
|
-
*
|
|
4514
|
-
* @
|
|
4515
|
-
* @returns {
|
|
4635
|
+
* sets Caption language for the meeting
|
|
4636
|
+
* @param {string} language
|
|
4637
|
+
* @returns {Promise}
|
|
4516
4638
|
*/
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
${event}`
|
|
4524
|
-
);
|
|
4639
|
+
public setCaptionLanguage(language: string) {
|
|
4640
|
+
return new Promise((resolve, reject) => {
|
|
4641
|
+
if (!this.isTranscriptionSupported()) {
|
|
4642
|
+
LoggerProxy.logger.error(
|
|
4643
|
+
'Meeting:index#setCaptionLanguage --> Webex Assistant is not enabled/supported'
|
|
4644
|
+
);
|
|
4525
4645
|
|
|
4526
|
-
|
|
4527
|
-
|
|
4646
|
+
reject(new Error('Webex Assistant is not enabled/supported'));
|
|
4647
|
+
}
|
|
4528
4648
|
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4649
|
+
try {
|
|
4650
|
+
const voiceaListenerCaptionUpdate = (payload) => {
|
|
4651
|
+
// @ts-ignore
|
|
4652
|
+
this.webex.internal.voicea.off(
|
|
4653
|
+
VOICEAEVENTS.CAPTION_LANGUAGE_UPDATE,
|
|
4654
|
+
voiceaListenerCaptionUpdate
|
|
4655
|
+
);
|
|
4656
|
+
const {statusCode} = payload;
|
|
4536
4657
|
|
|
4537
|
-
|
|
4658
|
+
if (statusCode === 200) {
|
|
4659
|
+
this.transcription.languageOptions = {
|
|
4660
|
+
...this.transcription.languageOptions,
|
|
4661
|
+
currentCaptionLanguage: language,
|
|
4662
|
+
};
|
|
4663
|
+
resolve(language);
|
|
4664
|
+
} else {
|
|
4665
|
+
reject(payload);
|
|
4666
|
+
}
|
|
4667
|
+
};
|
|
4668
|
+
// @ts-ignore
|
|
4669
|
+
this.webex.internal.voicea.on(
|
|
4670
|
+
VOICEAEVENTS.CAPTION_LANGUAGE_UPDATE,
|
|
4671
|
+
voiceaListenerCaptionUpdate
|
|
4672
|
+
);
|
|
4673
|
+
// @ts-ignore
|
|
4674
|
+
this.webex.internal.voicea.requestLanguage(language);
|
|
4675
|
+
} catch (error) {
|
|
4676
|
+
LoggerProxy.logger.error(`Meeting:index#setCaptionLanguage --> ${error}`);
|
|
4538
4677
|
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
reason: 'unexpected error: transcription LLM web socket connection error had occured.',
|
|
4542
|
-
event,
|
|
4543
|
-
});
|
|
4678
|
+
reject(error);
|
|
4679
|
+
}
|
|
4544
4680
|
});
|
|
4545
4681
|
}
|
|
4546
4682
|
|
|
4547
4683
|
/**
|
|
4548
|
-
*
|
|
4549
|
-
* @
|
|
4550
|
-
* @returns {Promise
|
|
4684
|
+
* sets Spoken language for the meeting
|
|
4685
|
+
* @param {string} language
|
|
4686
|
+
* @returns {Promise}
|
|
4551
4687
|
*/
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4688
|
+
public setSpokenLanguage(language: string) {
|
|
4689
|
+
return new Promise((resolve, reject) => {
|
|
4690
|
+
if (!this.isTranscriptionSupported()) {
|
|
4691
|
+
LoggerProxy.logger.error(
|
|
4692
|
+
'Meeting:index#setCaptionLanguage --> Webex Assistant is not enabled/supported'
|
|
4693
|
+
);
|
|
4694
|
+
|
|
4695
|
+
reject(new Error('Webex Assistant is not enabled/supported'));
|
|
4696
|
+
}
|
|
4697
|
+
|
|
4698
|
+
try {
|
|
4699
|
+
const voiceaListenerLanguageUpdate = (payload) => {
|
|
4700
|
+
// @ts-ignore
|
|
4701
|
+
this.webex.internal.voicea.off(
|
|
4702
|
+
VOICEAEVENTS.SPOKEN_LANGUAGE_UPDATE,
|
|
4703
|
+
voiceaListenerLanguageUpdate
|
|
4704
|
+
);
|
|
4705
|
+
const {languageCode} = payload;
|
|
4706
|
+
|
|
4707
|
+
if (languageCode) {
|
|
4708
|
+
this.transcription.languageOptions = {
|
|
4709
|
+
...this.transcription.languageOptions,
|
|
4710
|
+
currentSpokenLanguage: languageCode,
|
|
4711
|
+
};
|
|
4712
|
+
resolve(languageCode);
|
|
4713
|
+
} else {
|
|
4714
|
+
reject(payload);
|
|
4715
|
+
}
|
|
4716
|
+
};
|
|
4557
4717
|
|
|
4558
|
-
try {
|
|
4559
|
-
const {datachannelUrl} = this.locusInfo.info;
|
|
4560
|
-
// @ts-ignore - fix type
|
|
4561
|
-
const {
|
|
4562
|
-
body: {webSocketUrl},
|
|
4563
4718
|
// @ts-ignore
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
});
|
|
4719
|
+
this.webex.internal.voicea.on(
|
|
4720
|
+
VOICEAEVENTS.SPOKEN_LANGUAGE_UPDATE,
|
|
4721
|
+
voiceaListenerLanguageUpdate
|
|
4722
|
+
);
|
|
4569
4723
|
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4724
|
+
// @ts-ignore
|
|
4725
|
+
this.webex.internal.voicea.setSpokenLanguage(language);
|
|
4726
|
+
} catch (error) {
|
|
4727
|
+
LoggerProxy.logger.error(`Meeting:index#setSpokenLanguage --> ${error}`);
|
|
4574
4728
|
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
this.members
|
|
4580
|
-
);
|
|
4729
|
+
reject(error);
|
|
4730
|
+
}
|
|
4731
|
+
});
|
|
4732
|
+
}
|
|
4581
4733
|
|
|
4734
|
+
/**
|
|
4735
|
+
* This method will enable the transcription for the current meeting if the meeting has enabled/supports Webex Assistant
|
|
4736
|
+
* @param {Object} options object with spokenlanguage setting
|
|
4737
|
+
* @public
|
|
4738
|
+
* @returns {Promise<void>} a promise to open the WebSocket connection
|
|
4739
|
+
*/
|
|
4740
|
+
public async startTranscription(options?: {spokenLanguage?: string}) {
|
|
4741
|
+
if (this.isJoined()) {
|
|
4582
4742
|
LoggerProxy.logger.info(
|
|
4583
|
-
|
|
4584
|
-
opened LLM web socket connection successfully.`
|
|
4743
|
+
'Meeting:index#startTranscription --> Attempting to enable transcription!'
|
|
4585
4744
|
);
|
|
4586
4745
|
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
}
|
|
4592
|
-
|
|
4593
|
-
// retrieve and pass the payload
|
|
4594
|
-
this.transcription.subscribe((payload) => {
|
|
4595
|
-
Trigger.trigger(
|
|
4596
|
-
this,
|
|
4597
|
-
{
|
|
4598
|
-
file: 'meeting/index',
|
|
4599
|
-
function: 'join',
|
|
4600
|
-
},
|
|
4601
|
-
EVENT_TRIGGERS.MEETING_STARTED_RECEIVING_TRANSCRIPTION,
|
|
4602
|
-
payload
|
|
4603
|
-
);
|
|
4604
|
-
});
|
|
4746
|
+
try {
|
|
4747
|
+
if (!this.areVoiceaEventsSetup) {
|
|
4748
|
+
this.setUpVoiceaListeners();
|
|
4749
|
+
}
|
|
4605
4750
|
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4751
|
+
if (this.getCurUserType() === 'host') {
|
|
4752
|
+
// @ts-ignore
|
|
4753
|
+
await this.webex.internal.voicea.toggleTranscribing(true, options?.spokenLanguage);
|
|
4754
|
+
}
|
|
4755
|
+
} catch (error) {
|
|
4756
|
+
LoggerProxy.logger.error(`Meeting:index#startTranscription --> ${error}`);
|
|
4757
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.RECEIVE_TRANSCRIPTION_FAILURE, {
|
|
4758
|
+
correlation_id: this.correlationId,
|
|
4759
|
+
reason: error.message,
|
|
4760
|
+
stack: error.stack,
|
|
4761
|
+
});
|
|
4762
|
+
}
|
|
4763
|
+
} else {
|
|
4764
|
+
LoggerProxy.logger.error(
|
|
4765
|
+
`Meeting:index#startTranscription --> meeting joined : ${this.isJoined()}`
|
|
4766
|
+
);
|
|
4767
|
+
throw new Error('Meeting is not joined');
|
|
4616
4768
|
}
|
|
4617
4769
|
}
|
|
4618
4770
|
|
|
@@ -4655,13 +4807,37 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4655
4807
|
};
|
|
4656
4808
|
|
|
4657
4809
|
/**
|
|
4658
|
-
*
|
|
4659
|
-
* the web socket connection properly
|
|
4810
|
+
* This method stops receiving transcription for the current meeting
|
|
4660
4811
|
* @returns {void}
|
|
4661
4812
|
*/
|
|
4662
|
-
|
|
4813
|
+
stopTranscription() {
|
|
4663
4814
|
if (this.transcription) {
|
|
4664
|
-
|
|
4815
|
+
// @ts-ignore
|
|
4816
|
+
this.webex.internal.voicea.off(
|
|
4817
|
+
VOICEAEVENTS.VOICEA_ANNOUNCEMENT,
|
|
4818
|
+
this.voiceaListenerCallbacks[VOICEAEVENTS.VOICEA_ANNOUNCEMENT]
|
|
4819
|
+
);
|
|
4820
|
+
|
|
4821
|
+
// @ts-ignore
|
|
4822
|
+
this.webex.internal.voicea.off(
|
|
4823
|
+
VOICEAEVENTS.CAPTIONS_TURNED_ON,
|
|
4824
|
+
this.voiceaListenerCallbacks[VOICEAEVENTS.CAPTIONS_TURNED_ON]
|
|
4825
|
+
);
|
|
4826
|
+
|
|
4827
|
+
// @ts-ignore
|
|
4828
|
+
this.webex.internal.voicea.off(
|
|
4829
|
+
VOICEAEVENTS.EVA_COMMAND,
|
|
4830
|
+
this.voiceaListenerCallbacks[VOICEAEVENTS.EVA_COMMAND]
|
|
4831
|
+
);
|
|
4832
|
+
|
|
4833
|
+
// @ts-ignore
|
|
4834
|
+
this.webex.internal.voicea.off(
|
|
4835
|
+
VOICEAEVENTS.NEW_CAPTION,
|
|
4836
|
+
this.voiceaListenerCallbacks[VOICEAEVENTS.NEW_CAPTION]
|
|
4837
|
+
);
|
|
4838
|
+
|
|
4839
|
+
this.areVoiceaEventsSetup = false;
|
|
4840
|
+
this.triggerStopReceivingTranscriptionEvent();
|
|
4665
4841
|
}
|
|
4666
4842
|
}
|
|
4667
4843
|
|
|
@@ -4674,12 +4850,12 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4674
4850
|
private triggerStopReceivingTranscriptionEvent() {
|
|
4675
4851
|
LoggerProxy.logger.info(`
|
|
4676
4852
|
Meeting:index#stopReceivingTranscription -->
|
|
4677
|
-
closed
|
|
4853
|
+
closed voicea event listeners successfully.`);
|
|
4678
4854
|
|
|
4679
4855
|
Trigger.trigger(
|
|
4680
4856
|
this,
|
|
4681
4857
|
{
|
|
4682
|
-
file: 'meeting',
|
|
4858
|
+
file: 'meeting/index',
|
|
4683
4859
|
function: 'triggerStopReceivingTranscriptionEvent',
|
|
4684
4860
|
},
|
|
4685
4861
|
EVENT_TRIGGERS.MEETING_STOPPED_RECEIVING_TRANSCRIPTION
|
|
@@ -4905,48 +5081,33 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4905
5081
|
.then((join) => {
|
|
4906
5082
|
// @ts-ignore - config coming from registerPlugin
|
|
4907
5083
|
if (this.config.enableAutomaticLLM) {
|
|
4908
|
-
this.updateLLMConnection()
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
stack: error.stack,
|
|
4915
|
-
});
|
|
4916
|
-
});
|
|
4917
|
-
}
|
|
5084
|
+
this.updateLLMConnection()
|
|
5085
|
+
.catch((error) => {
|
|
5086
|
+
LoggerProxy.logger.error(
|
|
5087
|
+
'Meeting:index#join --> Transcription Socket Connection Failed',
|
|
5088
|
+
error
|
|
5089
|
+
);
|
|
4918
5090
|
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
5091
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.LLM_CONNECTION_AFTER_JOIN_FAILURE, {
|
|
5092
|
+
correlation_id: this.correlationId,
|
|
5093
|
+
reason: error?.message,
|
|
5094
|
+
stack: error.stack,
|
|
5095
|
+
});
|
|
5096
|
+
})
|
|
5097
|
+
.then(() => {
|
|
4926
5098
|
LoggerProxy.logger.info(
|
|
4927
|
-
'Meeting:index#join -->
|
|
5099
|
+
'Meeting:index#join --> Transcription Socket Connection Success'
|
|
4928
5100
|
);
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
reason: error?.message,
|
|
4940
|
-
stack: error.stack,
|
|
4941
|
-
}
|
|
4942
|
-
);
|
|
4943
|
-
});
|
|
4944
|
-
}
|
|
4945
|
-
}
|
|
4946
|
-
} else {
|
|
4947
|
-
LoggerProxy.logger.error(
|
|
4948
|
-
'Meeting:index#join --> Receving transcription is not supported on this platform'
|
|
4949
|
-
);
|
|
5101
|
+
Trigger.trigger(
|
|
5102
|
+
this,
|
|
5103
|
+
{
|
|
5104
|
+
file: 'meeting/index',
|
|
5105
|
+
function: 'join',
|
|
5106
|
+
},
|
|
5107
|
+
EVENT_TRIGGERS.MEETING_TRANSCRIPTION_CONNECTED,
|
|
5108
|
+
undefined
|
|
5109
|
+
);
|
|
5110
|
+
});
|
|
4950
5111
|
}
|
|
4951
5112
|
|
|
4952
5113
|
return join;
|
|
@@ -7377,7 +7538,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7377
7538
|
|
|
7378
7539
|
if (layoutType) {
|
|
7379
7540
|
if (!LAYOUT_TYPES.includes(layoutType)) {
|
|
7380
|
-
this.rejectWithErrorLog(
|
|
7541
|
+
return this.rejectWithErrorLog(
|
|
7381
7542
|
'Meeting:index#changeVideoLayout --> cannot change video layout, invalid layoutType received.'
|
|
7382
7543
|
);
|
|
7383
7544
|
}
|
|
@@ -7633,6 +7794,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7633
7794
|
if (roles.includes(SELF_ROLES.COHOST)) {
|
|
7634
7795
|
return 'cohost';
|
|
7635
7796
|
}
|
|
7797
|
+
if (roles.includes(SELF_ROLES.PRESENTER)) {
|
|
7798
|
+
return 'presenter';
|
|
7799
|
+
}
|
|
7636
7800
|
if (roles.includes(SELF_ROLES.ATTENDEE)) {
|
|
7637
7801
|
return 'attendee';
|
|
7638
7802
|
}
|
|
@@ -7723,8 +7887,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
7723
7887
|
this.queuedMediaUpdates = [];
|
|
7724
7888
|
|
|
7725
7889
|
if (this.transcription) {
|
|
7726
|
-
this.
|
|
7727
|
-
this.triggerStopReceivingTranscriptionEvent();
|
|
7890
|
+
this.stopTranscription();
|
|
7728
7891
|
this.transcription = undefined;
|
|
7729
7892
|
}
|
|
7730
7893
|
};
|
package/src/meeting/util.ts
CHANGED
|
@@ -202,7 +202,11 @@ const MeetingUtil = {
|
|
|
202
202
|
meeting.reconnectionManager.cleanUp();
|
|
203
203
|
})
|
|
204
204
|
.then(() => meeting.stopKeepAlive())
|
|
205
|
-
.then(() =>
|
|
205
|
+
.then(() => {
|
|
206
|
+
if (meeting.config?.enableAutomaticLLM) {
|
|
207
|
+
meeting.updateLLMConnection();
|
|
208
|
+
}
|
|
209
|
+
});
|
|
206
210
|
},
|
|
207
211
|
|
|
208
212
|
disconnectPhoneAudio: (meeting, phoneUrl) => {
|