@webex/internal-plugin-voicea 3.0.0-beta.39 → 3.0.0-beta.391

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/constants.js CHANGED
@@ -4,7 +4,7 @@ var _Object$defineProperty = require("@babel/runtime-corejs2/core-js/object/defi
4
4
  _Object$defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.VOICEA_RELAY_TYPES = exports.VOICEA = exports.TRANSCRIPTION_TYPE = exports.EVENT_TRIGGERS = void 0;
7
+ exports.VOICEA_RELAY_TYPES = exports.VOICEA = exports.TURN_ON_CAPTION_STATUS = exports.TRANSCRIPTION_TYPE = exports.EVENT_TRIGGERS = exports.ANNOUNCE_STATUS = void 0;
8
8
  var EVENT_TRIGGERS = {
9
9
  VOICEA_ANNOUNCEMENT: 'voicea:announcement',
10
10
  CAPTION_LANGUAGE_UPDATE: 'voicea:captionLanguageUpdate',
@@ -37,4 +37,16 @@ var TRANSCRIPTION_TYPE = {
37
37
  exports.TRANSCRIPTION_TYPE = TRANSCRIPTION_TYPE;
38
38
  var VOICEA = 'voicea';
39
39
  exports.VOICEA = VOICEA;
40
+ var ANNOUNCE_STATUS = {
41
+ IDLE: 'idle',
42
+ JOINED: 'joined',
43
+ JOINING: 'joining'
44
+ };
45
+ exports.ANNOUNCE_STATUS = ANNOUNCE_STATUS;
46
+ var TURN_ON_CAPTION_STATUS = {
47
+ IDLE: 'idle',
48
+ ENABLED: 'enabled',
49
+ SENDING: 'sending'
50
+ };
51
+ exports.TURN_ON_CAPTION_STATUS = TURN_ON_CAPTION_STATUS;
40
52
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["EVENT_TRIGGERS","VOICEA_ANNOUNCEMENT","CAPTION_LANGUAGE_UPDATE","SPOKEN_LANGUAGE_UPDATE","CAPTIONS_TURNED_ON","TRANSCRIBING_ON","TRANSCRIBING_OFF","NEW_CAPTION","EVA_COMMAND","HIGHLIGHT_CREATED","VOICEA_RELAY_TYPES","ANNOUNCEMENT","CLIENT_ANNOUNCEMENT","TRANSLATION_REQUEST","TRANSLATION_RESPONSE","TRANSCRIPTION","TRANSCRIPTION_TYPE","UNKNOWN","EVA_WAKE","EVA_THANKS","EVA_CANCEL","TRANSCRIPT_INTERIM_RESULTS","TRANSCRIPT_FINAL_RESULT","VOICEA"],"sources":["constants.ts"],"sourcesContent":["export const EVENT_TRIGGERS = {\n VOICEA_ANNOUNCEMENT: 'voicea:announcement',\n CAPTION_LANGUAGE_UPDATE: 'voicea:captionLanguageUpdate',\n SPOKEN_LANGUAGE_UPDATE: 'voicea:spokenLanguageUpdate',\n CAPTIONS_TURNED_ON: 'voicea:captionOn',\n TRANSCRIBING_ON: 'voicea:transcribingOn',\n TRANSCRIBING_OFF: 'voicea:transcribingOff',\n\n NEW_CAPTION: 'voicea:newCaption',\n EVA_COMMAND: 'voicea:wxa',\n HIGHLIGHT_CREATED: 'voicea:highlightCreated',\n};\n\nexport const VOICEA_RELAY_TYPES = {\n ANNOUNCEMENT: 'voicea.annc',\n CLIENT_ANNOUNCEMENT: 'client.annc',\n TRANSLATION_REQUEST: 'voicea.transl.req',\n TRANSLATION_RESPONSE: 'voicea.transl.rsp',\n TRANSCRIPTION: 'voicea.transcription',\n};\n\nexport const TRANSCRIPTION_TYPE = {\n UNKNOWN: 'unknown',\n EVA_WAKE: 'eva_wake',\n EVA_THANKS: 'eva_thanks',\n EVA_CANCEL: 'eva_cancel',\n HIGHLIGHT_CREATED: 'highlight_created',\n TRANSCRIPT_INTERIM_RESULTS: 'transcript_interim_results',\n TRANSCRIPT_FINAL_RESULT: 'transcript_final_result',\n};\n\nexport const VOICEA = 'voicea';\n"],"mappings":";;;;;;;AAAO,IAAMA,cAAc,GAAG;EAC5BC,mBAAmB,EAAE,qBAAqB;EAC1CC,uBAAuB,EAAE,8BAA8B;EACvDC,sBAAsB,EAAE,6BAA6B;EACrDC,kBAAkB,EAAE,kBAAkB;EACtCC,eAAe,EAAE,uBAAuB;EACxCC,gBAAgB,EAAE,wBAAwB;EAE1CC,WAAW,EAAE,mBAAmB;EAChCC,WAAW,EAAE,YAAY;EACzBC,iBAAiB,EAAE;AACrB,CAAC;AAAC;AAEK,IAAMC,kBAAkB,GAAG;EAChCC,YAAY,EAAE,aAAa;EAC3BC,mBAAmB,EAAE,aAAa;EAClCC,mBAAmB,EAAE,mBAAmB;EACxCC,oBAAoB,EAAE,mBAAmB;EACzCC,aAAa,EAAE;AACjB,CAAC;AAAC;AAEK,IAAMC,kBAAkB,GAAG;EAChCC,OAAO,EAAE,SAAS;EAClBC,QAAQ,EAAE,UAAU;EACpBC,UAAU,EAAE,YAAY;EACxBC,UAAU,EAAE,YAAY;EACxBX,iBAAiB,EAAE,mBAAmB;EACtCY,0BAA0B,EAAE,4BAA4B;EACxDC,uBAAuB,EAAE;AAC3B,CAAC;AAAC;AAEK,IAAMC,MAAM,GAAG,QAAQ;AAAC"}
1
+ {"version":3,"names":["EVENT_TRIGGERS","VOICEA_ANNOUNCEMENT","CAPTION_LANGUAGE_UPDATE","SPOKEN_LANGUAGE_UPDATE","CAPTIONS_TURNED_ON","TRANSCRIBING_ON","TRANSCRIBING_OFF","NEW_CAPTION","EVA_COMMAND","HIGHLIGHT_CREATED","VOICEA_RELAY_TYPES","ANNOUNCEMENT","CLIENT_ANNOUNCEMENT","TRANSLATION_REQUEST","TRANSLATION_RESPONSE","TRANSCRIPTION","TRANSCRIPTION_TYPE","UNKNOWN","EVA_WAKE","EVA_THANKS","EVA_CANCEL","TRANSCRIPT_INTERIM_RESULTS","TRANSCRIPT_FINAL_RESULT","VOICEA","ANNOUNCE_STATUS","IDLE","JOINED","JOINING","TURN_ON_CAPTION_STATUS","ENABLED","SENDING"],"sources":["constants.ts"],"sourcesContent":["export const EVENT_TRIGGERS = {\n VOICEA_ANNOUNCEMENT: 'voicea:announcement',\n CAPTION_LANGUAGE_UPDATE: 'voicea:captionLanguageUpdate',\n SPOKEN_LANGUAGE_UPDATE: 'voicea:spokenLanguageUpdate',\n CAPTIONS_TURNED_ON: 'voicea:captionOn',\n TRANSCRIBING_ON: 'voicea:transcribingOn',\n TRANSCRIBING_OFF: 'voicea:transcribingOff',\n\n NEW_CAPTION: 'voicea:newCaption',\n EVA_COMMAND: 'voicea:wxa',\n HIGHLIGHT_CREATED: 'voicea:highlightCreated',\n};\n\nexport const VOICEA_RELAY_TYPES = {\n ANNOUNCEMENT: 'voicea.annc',\n CLIENT_ANNOUNCEMENT: 'client.annc',\n TRANSLATION_REQUEST: 'voicea.transl.req',\n TRANSLATION_RESPONSE: 'voicea.transl.rsp',\n TRANSCRIPTION: 'voicea.transcription',\n};\n\nexport const TRANSCRIPTION_TYPE = {\n UNKNOWN: 'unknown',\n EVA_WAKE: 'eva_wake',\n EVA_THANKS: 'eva_thanks',\n EVA_CANCEL: 'eva_cancel',\n HIGHLIGHT_CREATED: 'highlight_created',\n TRANSCRIPT_INTERIM_RESULTS: 'transcript_interim_results',\n TRANSCRIPT_FINAL_RESULT: 'transcript_final_result',\n};\n\nexport const VOICEA = 'voicea';\n\nexport const ANNOUNCE_STATUS = {\n IDLE: 'idle',\n JOINED: 'joined',\n JOINING: 'joining',\n};\n\nexport const TURN_ON_CAPTION_STATUS = {\n IDLE: 'idle',\n ENABLED: 'enabled',\n SENDING: 'sending',\n};\n"],"mappings":";;;;;;;AAAO,IAAMA,cAAc,GAAG;EAC5BC,mBAAmB,EAAE,qBAAqB;EAC1CC,uBAAuB,EAAE,8BAA8B;EACvDC,sBAAsB,EAAE,6BAA6B;EACrDC,kBAAkB,EAAE,kBAAkB;EACtCC,eAAe,EAAE,uBAAuB;EACxCC,gBAAgB,EAAE,wBAAwB;EAE1CC,WAAW,EAAE,mBAAmB;EAChCC,WAAW,EAAE,YAAY;EACzBC,iBAAiB,EAAE;AACrB,CAAC;AAAC;AAEK,IAAMC,kBAAkB,GAAG;EAChCC,YAAY,EAAE,aAAa;EAC3BC,mBAAmB,EAAE,aAAa;EAClCC,mBAAmB,EAAE,mBAAmB;EACxCC,oBAAoB,EAAE,mBAAmB;EACzCC,aAAa,EAAE;AACjB,CAAC;AAAC;AAEK,IAAMC,kBAAkB,GAAG;EAChCC,OAAO,EAAE,SAAS;EAClBC,QAAQ,EAAE,UAAU;EACpBC,UAAU,EAAE,YAAY;EACxBC,UAAU,EAAE,YAAY;EACxBX,iBAAiB,EAAE,mBAAmB;EACtCY,0BAA0B,EAAE,4BAA4B;EACxDC,uBAAuB,EAAE;AAC3B,CAAC;AAAC;AAEK,IAAMC,MAAM,GAAG,QAAQ;AAAC;AAExB,IAAMC,eAAe,GAAG;EAC7BC,IAAI,EAAE,MAAM;EACZC,MAAM,EAAE,QAAQ;EAChBC,OAAO,EAAE;AACX,CAAC;AAAC;AAEK,IAAMC,sBAAsB,GAAG;EACpCH,IAAI,EAAE,MAAM;EACZI,OAAO,EAAE,SAAS;EAClBC,OAAO,EAAE;AACX,CAAC;AAAC"}
package/dist/voicea.js CHANGED
@@ -44,16 +44,17 @@ var VoiceaChannel = /*#__PURE__*/function (_WebexPlugin) {
44
44
  _this = _super.call.apply(_super, [this].concat(args));
45
45
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "namespace", _constants.VOICEA);
46
46
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "seqNum", void 0);
47
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "hasVoiceaJoined", void 0);
48
47
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "areCaptionsEnabled", void 0);
49
48
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "hasSubscribedToEvents", false);
50
49
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "vmcDeviceId", void 0);
50
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "announceStatus", void 0);
51
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "captionStatus", void 0);
51
52
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "eventProcessor", function (e) {
52
53
  _this.seqNum = e.sequenceNumber + 1;
53
54
  switch (e.data.relayType) {
54
55
  case _constants.VOICEA_RELAY_TYPES.ANNOUNCEMENT:
55
56
  _this.vmcDeviceId = e.headers.from;
56
- _this.hasVoiceaJoined = true;
57
+ _this.announceStatus = _constants.ANNOUNCE_STATUS.JOINED;
57
58
  _this.processAnnouncementMessage(e.data.voiceaPayload);
58
59
  break;
59
60
  case _constants.VOICEA_RELAY_TYPES.TRANSLATION_RESPONSE:
@@ -159,8 +160,7 @@ var VoiceaChannel = /*#__PURE__*/function (_WebexPlugin) {
159
160
  }, _constants.EVENT_TRIGGERS.VOICEA_ANNOUNCEMENT, voiceaLanguageOptions);
160
161
  });
161
162
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "sendAnnouncement", function () {
162
- // @ts-ignore
163
- if (_this.hasVoiceaJoined || !_this.webex.internal.llm.isConnected()) return;
163
+ _this.announceStatus = _constants.ANNOUNCE_STATUS.JOINING;
164
164
  _this.listenToEvents();
165
165
  // @ts-ignore
166
166
  _this.webex.internal.llm.socket.send({
@@ -228,34 +228,64 @@ var VoiceaChannel = /*#__PURE__*/function (_WebexPlugin) {
228
228
  });
229
229
  _this.seqNum += 1;
230
230
  });
231
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "requestTurnOnCaptions", function () {
232
+ _this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.SENDING;
233
+ // @ts-ignore
234
+ // eslint-disable-next-line newline-before-return
235
+ return _this.request({
236
+ method: 'PUT',
237
+ // @ts-ignore
238
+ url: "".concat(_this.webex.internal.llm.getLocusUrl(), "/controls/"),
239
+ body: {
240
+ transcribe: {
241
+ caption: true
242
+ }
243
+ }
244
+ }).then(function () {
245
+ _pluginMeetings.TriggerProxy.trigger((0, _assertThisInitialized2.default)(_this), {
246
+ file: 'voicea',
247
+ function: 'turnOnCaptions'
248
+ }, _constants.EVENT_TRIGGERS.CAPTIONS_TURNED_ON);
249
+ _this.areCaptionsEnabled = true;
250
+ _this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.ENABLED;
251
+ _this.announce();
252
+ }).catch(function () {
253
+ _this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.IDLE;
254
+ throw new Error('turn on captions fail');
255
+ });
256
+ });
257
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isAnnounceProcessing", function () {
258
+ return [_constants.ANNOUNCE_STATUS.JOINING, _constants.ANNOUNCE_STATUS.JOINED].includes(_this.announceStatus);
259
+ });
260
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "announce", function () {
261
+ if (_this.isAnnounceProcessing()) return;
262
+ // @ts-ignore
263
+ if (!_this.webex.internal.llm.isConnected()) {
264
+ throw new Error('voicea can not announce before llm connected');
265
+ }
266
+ _this.sendAnnouncement();
267
+ });
268
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "isCaptionProcessing", function () {
269
+ return [_constants.TURN_ON_CAPTION_STATUS.SENDING, _constants.TURN_ON_CAPTION_STATUS.ENABLED].includes(_this.captionStatus);
270
+ });
231
271
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "turnOnCaptions", /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
232
272
  return _regenerator.default.wrap(function _callee$(_context) {
233
273
  while (1) switch (_context.prev = _context.next) {
234
274
  case 0:
235
- if (!(_this.hasVoiceaJoined && _this.areCaptionsEnabled)) {
275
+ if (!_this.isCaptionProcessing()) {
236
276
  _context.next = 2;
237
277
  break;
238
278
  }
239
279
  return _context.abrupt("return", undefined);
240
280
  case 2:
241
- return _context.abrupt("return", _this.request({
242
- method: 'PUT',
243
- // @ts-ignore
244
- url: "".concat(_this.webex.internal.llm.getLocusUrl(), "/controls/"),
245
- body: {
246
- transcribe: {
247
- caption: true
248
- }
249
- }
250
- }).then(function () {
251
- _pluginMeetings.TriggerProxy.trigger((0, _assertThisInitialized2.default)(_this), {
252
- file: 'voicea',
253
- function: 'turnOnCaptions'
254
- }, _constants.EVENT_TRIGGERS.CAPTIONS_TURNED_ON);
255
- _this.areCaptionsEnabled = true;
256
- _this.sendAnnouncement();
257
- }));
258
- case 3:
281
+ if (_this.webex.internal.llm.isConnected()) {
282
+ _context.next = 4;
283
+ break;
284
+ }
285
+ throw new Error('can not turn on captions before llm connected');
286
+ case 4:
287
+ return _context.abrupt("return", _this.requestTurnOnCaptions());
288
+ case 5:
259
289
  case "end":
260
290
  return _context.stop();
261
291
  }
@@ -276,7 +306,7 @@ var VoiceaChannel = /*#__PURE__*/function (_WebexPlugin) {
276
306
  }
277
307
  }
278
308
  }).then(function () {
279
- if (activate && !_this.areCaptionsEnabled && !_this.hasVoiceaJoined) _this.turnOnCaptions();
309
+ if (activate && !_this.areCaptionsEnabled) _this.turnOnCaptions();
280
310
  }));
281
311
  case 1:
282
312
  case "end":
@@ -288,10 +318,17 @@ var VoiceaChannel = /*#__PURE__*/function (_WebexPlugin) {
288
318
  return _ref2.apply(this, arguments);
289
319
  };
290
320
  }());
321
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getCaptionStatus", function () {
322
+ return _this.captionStatus;
323
+ });
324
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "getAnnounceStatus", function () {
325
+ return _this.announceStatus;
326
+ });
291
327
  _this.seqNum = 1;
292
- _this.hasVoiceaJoined = false;
293
328
  _this.areCaptionsEnabled = false;
294
329
  _this.vmcDeviceId = undefined;
330
+ _this.announceStatus = _constants.ANNOUNCE_STATUS.IDLE;
331
+ _this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.IDLE;
295
332
  return _this;
296
333
  }
297
334
 
@@ -320,16 +357,20 @@ var VoiceaChannel = /*#__PURE__*/function (_WebexPlugin) {
320
357
  }
321
358
  }
322
359
 
323
- // @ts-ignore
360
+ /**
361
+ * Listen to websocket messages
362
+ * @returns {void}
363
+ */
324
364
  }, {
325
365
  key: "deregisterEvents",
326
366
  value: function deregisterEvents() {
327
- this.hasVoiceaJoined = false;
328
367
  this.areCaptionsEnabled = false;
329
368
  this.vmcDeviceId = undefined;
330
369
  // @ts-ignore
331
370
  this.webex.internal.llm.off('event:relay.event', this.eventProcessor);
332
371
  this.hasSubscribedToEvents = false;
372
+ this.announceStatus = _constants.ANNOUNCE_STATUS.IDLE;
373
+ this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.IDLE;
333
374
  }
334
375
  }]);
335
376
  return VoiceaChannel;
@@ -1 +1 @@
1
- {"version":3,"names":["VoiceaChannel","args","VOICEA","e","seqNum","sequenceNumber","data","relayType","VOICEA_RELAY_TYPES","ANNOUNCEMENT","vmcDeviceId","headers","from","hasVoiceaJoined","processAnnouncementMessage","voiceaPayload","TRANSLATION_RESPONSE","processCaptionLanguageResponse","TRANSCRIPTION","processTranscription","type","TRANSCRIPTION_TYPE","TRANSCRIPT_INTERIM_RESULTS","Trigger","trigger","file","function","EVENT_TRIGGERS","NEW_CAPTION","isFinal","transcriptId","transcript_id","transcripts","TRANSCRIPT_FINAL_RESULT","transcript","csis","text","transcriptLanguageCode","transcript_language_code","timestamp","millisToMinutesAndSeconds","end_millis","HIGHLIGHT_CREATED","highlight","highlightId","highlight_id","highlightLabel","highlight_label","highlightSource","highlight_source","EVA_THANKS","EVA_COMMAND","isListening","command_response","EVA_WAKE","EVA_CANCEL","statusCode","CAPTION_LANGUAGE_UPDATE","errorCode","errorMessage","message","voiceaLanguageOptions","captionLanguages","translation","allowed_languages","maxLanguages","max_languages","spokenLanguages","ASR","spoken_languages","VOICEA_ANNOUNCEMENT","webex","internal","llm","isConnected","listenToEvents","socket","send","id","recipients","route","getBinding","clientPayload","version","eventType","CLIENT_ANNOUNCEMENT","trackingId","config","trackingIdPrefix","uuid","v4","toString","languageCode","request","method","url","getLocusUrl","body","then","SPOKEN_LANGUAGE_UPDATE","to","translationLanguage","TRANSLATION_REQUEST","areCaptionsEnabled","undefined","transcribe","caption","CAPTIONS_TURNED_ON","sendAnnouncement","activate","transcribing","turnOnCaptions","hasSubscribedToEvents","on","eventProcessor","off","WebexPlugin"],"sources":["voicea.ts"],"sourcesContent":["import uuid from 'uuid';\nimport {TriggerProxy as Trigger} from '@webex/plugin-meetings';\nimport {WebexPlugin, config} from '@webex/webex-core';\n\nimport {EVENT_TRIGGERS, VOICEA_RELAY_TYPES, TRANSCRIPTION_TYPE, VOICEA} from './constants';\n// eslint-disable-next-line no-unused-vars\nimport {\n AnnouncementPayload,\n CaptionLanguageResponse,\n TranscriptionResponse,\n IVoiceaChannel,\n} from './voicea.types';\nimport {millisToMinutesAndSeconds} from './utils';\n\n/**\n * @description VoiceaChannel to hold single instance of LLM\n * @export\n * @class VoiceaChannel\n */\nexport class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {\n namespace = VOICEA;\n\n private seqNum: number;\n\n private hasVoiceaJoined: boolean;\n\n private areCaptionsEnabled: boolean;\n\n private hasSubscribedToEvents = false;\n\n private vmcDeviceId?: string;\n\n /**\n * @param {Object} e\n * @returns {undefined}\n */\n\n private eventProcessor = (e) => {\n this.seqNum = e.sequenceNumber + 1;\n switch (e.data.relayType) {\n case VOICEA_RELAY_TYPES.ANNOUNCEMENT:\n this.vmcDeviceId = e.headers.from;\n this.hasVoiceaJoined = true;\n this.processAnnouncementMessage(e.data.voiceaPayload);\n break;\n case VOICEA_RELAY_TYPES.TRANSLATION_RESPONSE:\n this.processCaptionLanguageResponse(e.data.voiceaPayload);\n break;\n case VOICEA_RELAY_TYPES.TRANSCRIPTION:\n this.processTranscription(e.data.voiceaPayload);\n break;\n default:\n break;\n }\n };\n\n /**\n * Listen to websocket messages\n * @returns {undefined}\n */\n private listenToEvents() {\n if (!this.hasSubscribedToEvents) {\n // @ts-ignore\n this.webex.internal.llm.on('event:relay.event', this.eventProcessor);\n this.hasSubscribedToEvents = true;\n }\n }\n\n // @ts-ignore\n public deregisterEvents() {\n this.hasVoiceaJoined = false;\n this.areCaptionsEnabled = false;\n this.vmcDeviceId = undefined;\n // @ts-ignore\n this.webex.internal.llm.off('event:relay.event', this.eventProcessor);\n this.hasSubscribedToEvents = false;\n }\n\n /**\n * Initializes Voicea plugin\n * @param {any} args\n */\n constructor(...args) {\n super(...args);\n this.seqNum = 1;\n this.hasVoiceaJoined = false;\n this.areCaptionsEnabled = false;\n this.vmcDeviceId = undefined;\n }\n\n /**\n * Process Transcript and send alert\n * @param {TranscriptionResponse} voiceaPayload\n * @returns {void}\n */\n private processTranscription = (voiceaPayload: TranscriptionResponse): void => {\n switch (voiceaPayload.type) {\n case TRANSCRIPTION_TYPE.TRANSCRIPT_INTERIM_RESULTS:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.NEW_CAPTION,\n {\n isFinal: false,\n transcriptId: voiceaPayload.transcript_id,\n transcripts: voiceaPayload.transcripts,\n }\n );\n break;\n\n case TRANSCRIPTION_TYPE.TRANSCRIPT_FINAL_RESULT:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.NEW_CAPTION,\n {\n isFinal: true,\n transcriptId: voiceaPayload.transcript_id,\n transcript: {\n csis: voiceaPayload.csis,\n text: voiceaPayload.transcript.text,\n transcriptLanguageCode: voiceaPayload.transcript.transcript_language_code,\n },\n timestamp: millisToMinutesAndSeconds(voiceaPayload.transcript.end_millis),\n }\n );\n break;\n\n case TRANSCRIPTION_TYPE.HIGHLIGHT_CREATED:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.HIGHLIGHT_CREATED,\n {\n csis: voiceaPayload.highlight.csis,\n highlightId: voiceaPayload.highlight.highlight_id,\n text: voiceaPayload.highlight.transcript,\n highlightLabel: voiceaPayload.highlight.highlight_label,\n highlightSource: voiceaPayload.highlight.highlight_source,\n timestamp: millisToMinutesAndSeconds(voiceaPayload.highlight.end_millis),\n }\n );\n break;\n\n case TRANSCRIPTION_TYPE.EVA_THANKS:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.EVA_COMMAND,\n {\n isListening: false,\n text: voiceaPayload.command_response,\n }\n );\n break;\n\n case TRANSCRIPTION_TYPE.EVA_WAKE:\n case TRANSCRIPTION_TYPE.EVA_CANCEL:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.EVA_COMMAND,\n {\n isListening: voiceaPayload.type === TRANSCRIPTION_TYPE.EVA_WAKE,\n }\n );\n break;\n\n default:\n break;\n }\n };\n\n /**\n * Processes Caption Language Response\n * @param {CaptionLanguageResponse} voiceaPayload\n * @returns {void}\n */\n private processCaptionLanguageResponse = (voiceaPayload: CaptionLanguageResponse): void => {\n if (voiceaPayload.statusCode === 200) {\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processCaptionLanguageResponse',\n },\n EVENT_TRIGGERS.CAPTION_LANGUAGE_UPDATE,\n {statusCode: 200}\n );\n } else {\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processCaptionLanguageResponse',\n },\n EVENT_TRIGGERS.CAPTION_LANGUAGE_UPDATE,\n {statusCode: voiceaPayload.errorCode, errorMessage: voiceaPayload.message}\n );\n }\n };\n\n /**\n * processes voicea announcement response and triggers event\n * @param {Object} voiceaPayload\n * @returns {void}\n */\n private processAnnouncementMessage = (voiceaPayload: AnnouncementPayload): void => {\n const voiceaLanguageOptions = {\n captionLanguages: voiceaPayload?.translation?.allowed_languages ?? [],\n maxLanguages: voiceaPayload?.translation?.max_languages ?? 0,\n spokenLanguages: voiceaPayload?.ASR?.spoken_languages ?? [],\n };\n\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processAnnouncementMessage',\n },\n EVENT_TRIGGERS.VOICEA_ANNOUNCEMENT,\n voiceaLanguageOptions\n );\n };\n\n /**\n * Sends Announcement to add voicea to the meeting\n * @returns {void}\n */\n private sendAnnouncement = (): void => {\n // @ts-ignore\n if (this.hasVoiceaJoined || !this.webex.internal.llm.isConnected()) return;\n\n this.listenToEvents();\n // @ts-ignore\n this.webex.internal.llm.socket.send({\n id: `${this.seqNum}`,\n type: 'publishRequest',\n recipients: {\n // @ts-ignore\n route: this.webex.internal.llm.getBinding(),\n },\n headers: {},\n data: {\n clientPayload: {\n version: 'v2',\n },\n eventType: 'relay.event',\n relayType: VOICEA_RELAY_TYPES.CLIENT_ANNOUNCEMENT,\n },\n trackingId: `${config.trackingIdPrefix}_${uuid.v4().toString()}`,\n });\n this.seqNum += 1;\n };\n\n /**\n * Set Spoken Language for the meeting\n * @param {string} languageCode\n * @returns {Promise}\n */\n public setSpokenLanguage = (languageCode: string): Promise<void> =>\n // @ts-ignore\n this.request({\n method: 'PUT',\n // @ts-ignore\n url: `${this.webex.internal.llm.getLocusUrl()}/controls/`,\n body: {\n languageCode,\n },\n }).then(() => {\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'setSpokenLanguage',\n },\n EVENT_TRIGGERS.SPOKEN_LANGUAGE_UPDATE,\n {languageCode}\n );\n });\n\n /**\n * Request Language translation\n * @param {string} languageCode\n * @returns {void}\n */\n public requestLanguage = (languageCode: string): void => {\n // @ts-ignore\n if (!this.webex.internal.llm.isConnected()) return;\n // @ts-ignore\n this.webex.internal.llm.socket.send({\n id: `${this.seqNum}`,\n type: 'publishRequest',\n recipients: {\n // @ts-ignore\n route: this.webex.internal.llm.getBinding(),\n },\n headers: {\n to: this.vmcDeviceId,\n },\n data: {\n clientPayload: {\n translationLanguage: languageCode,\n id: uuid.v4(),\n },\n eventType: 'relay.event',\n relayType: VOICEA_RELAY_TYPES.TRANSLATION_REQUEST,\n },\n trackingId: `${config.trackingIdPrefix}_${uuid.v4().toString()}`,\n });\n this.seqNum += 1;\n };\n\n /**\n * Turn on Captions\n * @returns {Promise}\n */\n public turnOnCaptions = async (): undefined | Promise<void> => {\n if (this.hasVoiceaJoined && this.areCaptionsEnabled) return undefined;\n // @ts-ignore\n // eslint-disable-next-line newline-before-return\n return this.request({\n method: 'PUT',\n // @ts-ignore\n url: `${this.webex.internal.llm.getLocusUrl()}/controls/`,\n body: {\n transcribe: {caption: true},\n },\n }).then(() => {\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'turnOnCaptions',\n },\n EVENT_TRIGGERS.CAPTIONS_TURNED_ON\n );\n this.areCaptionsEnabled = true;\n this.sendAnnouncement();\n });\n };\n\n /**\n * Toggle transcribing for highlights\n * @param {bool} activate if true transcribing is turned on\n * @returns {Promise}\n */\n public toggleTranscribing = async (activate: boolean): undefined | Promise<void> => {\n // @ts-ignore\n return this.request({\n method: 'PUT',\n // @ts-ignore\n url: `${this.webex.internal.llm.getLocusUrl()}/controls/`,\n body: {\n transcribe: {transcribing: activate},\n },\n }).then(() => {\n if (activate && !this.areCaptionsEnabled && !this.hasVoiceaJoined) this.turnOnCaptions();\n });\n };\n}\n\nexport default VoiceaChannel;\n"],"mappings":"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"}
1
+ {"version":3,"names":["VoiceaChannel","args","VOICEA","e","seqNum","sequenceNumber","data","relayType","VOICEA_RELAY_TYPES","ANNOUNCEMENT","vmcDeviceId","headers","from","announceStatus","ANNOUNCE_STATUS","JOINED","processAnnouncementMessage","voiceaPayload","TRANSLATION_RESPONSE","processCaptionLanguageResponse","TRANSCRIPTION","processTranscription","type","TRANSCRIPTION_TYPE","TRANSCRIPT_INTERIM_RESULTS","Trigger","trigger","file","function","EVENT_TRIGGERS","NEW_CAPTION","isFinal","transcriptId","transcript_id","transcripts","TRANSCRIPT_FINAL_RESULT","transcript","csis","text","transcriptLanguageCode","transcript_language_code","timestamp","millisToMinutesAndSeconds","end_millis","HIGHLIGHT_CREATED","highlight","highlightId","highlight_id","highlightLabel","highlight_label","highlightSource","highlight_source","EVA_THANKS","EVA_COMMAND","isListening","command_response","EVA_WAKE","EVA_CANCEL","statusCode","CAPTION_LANGUAGE_UPDATE","errorCode","errorMessage","message","voiceaLanguageOptions","captionLanguages","translation","allowed_languages","maxLanguages","max_languages","spokenLanguages","ASR","spoken_languages","VOICEA_ANNOUNCEMENT","JOINING","listenToEvents","webex","internal","llm","socket","send","id","recipients","route","getBinding","clientPayload","version","eventType","CLIENT_ANNOUNCEMENT","trackingId","config","trackingIdPrefix","uuid","v4","toString","languageCode","request","method","url","getLocusUrl","body","then","SPOKEN_LANGUAGE_UPDATE","isConnected","to","translationLanguage","TRANSLATION_REQUEST","captionStatus","TURN_ON_CAPTION_STATUS","SENDING","transcribe","caption","CAPTIONS_TURNED_ON","areCaptionsEnabled","ENABLED","announce","catch","IDLE","Error","includes","isAnnounceProcessing","sendAnnouncement","isCaptionProcessing","undefined","requestTurnOnCaptions","activate","transcribing","turnOnCaptions","hasSubscribedToEvents","on","eventProcessor","off","WebexPlugin"],"sources":["voicea.ts"],"sourcesContent":["import uuid from 'uuid';\nimport {TriggerProxy as Trigger} from '@webex/plugin-meetings';\nimport {WebexPlugin, config} from '@webex/webex-core';\n\nimport {\n EVENT_TRIGGERS,\n VOICEA_RELAY_TYPES,\n TRANSCRIPTION_TYPE,\n VOICEA,\n ANNOUNCE_STATUS,\n TURN_ON_CAPTION_STATUS,\n} from './constants';\n// eslint-disable-next-line no-unused-vars\nimport {\n AnnouncementPayload,\n CaptionLanguageResponse,\n TranscriptionResponse,\n IVoiceaChannel,\n} from './voicea.types';\nimport {millisToMinutesAndSeconds} from './utils';\n\n/**\n * @description VoiceaChannel to hold single instance of LLM\n * @export\n * @class VoiceaChannel\n */\nexport class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {\n namespace = VOICEA;\n\n private seqNum: number;\n\n private areCaptionsEnabled: boolean;\n\n private hasSubscribedToEvents = false;\n\n private vmcDeviceId?: string;\n\n private announceStatus: string;\n\n private captionStatus: string;\n\n /**\n * @param {Object} e\n * @returns {undefined}\n */\n\n private eventProcessor = (e) => {\n this.seqNum = e.sequenceNumber + 1;\n switch (e.data.relayType) {\n case VOICEA_RELAY_TYPES.ANNOUNCEMENT:\n this.vmcDeviceId = e.headers.from;\n this.announceStatus = ANNOUNCE_STATUS.JOINED;\n this.processAnnouncementMessage(e.data.voiceaPayload);\n break;\n case VOICEA_RELAY_TYPES.TRANSLATION_RESPONSE:\n this.processCaptionLanguageResponse(e.data.voiceaPayload);\n break;\n case VOICEA_RELAY_TYPES.TRANSCRIPTION:\n this.processTranscription(e.data.voiceaPayload);\n break;\n default:\n break;\n }\n };\n\n /**\n * Listen to websocket messages\n * @returns {undefined}\n */\n private listenToEvents() {\n if (!this.hasSubscribedToEvents) {\n // @ts-ignore\n this.webex.internal.llm.on('event:relay.event', this.eventProcessor);\n this.hasSubscribedToEvents = true;\n }\n }\n\n /**\n * Listen to websocket messages\n * @returns {void}\n */\n public deregisterEvents() {\n this.areCaptionsEnabled = false;\n this.vmcDeviceId = undefined;\n // @ts-ignore\n this.webex.internal.llm.off('event:relay.event', this.eventProcessor);\n this.hasSubscribedToEvents = false;\n this.announceStatus = ANNOUNCE_STATUS.IDLE;\n this.captionStatus = TURN_ON_CAPTION_STATUS.IDLE;\n }\n\n /**\n * Initializes Voicea plugin\n * @param {any} args\n */\n constructor(...args) {\n super(...args);\n this.seqNum = 1;\n this.areCaptionsEnabled = false;\n this.vmcDeviceId = undefined;\n this.announceStatus = ANNOUNCE_STATUS.IDLE;\n this.captionStatus = TURN_ON_CAPTION_STATUS.IDLE;\n }\n\n /**\n * Process Transcript and send alert\n * @param {TranscriptionResponse} voiceaPayload\n * @returns {void}\n */\n private processTranscription = (voiceaPayload: TranscriptionResponse): void => {\n switch (voiceaPayload.type) {\n case TRANSCRIPTION_TYPE.TRANSCRIPT_INTERIM_RESULTS:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.NEW_CAPTION,\n {\n isFinal: false,\n transcriptId: voiceaPayload.transcript_id,\n transcripts: voiceaPayload.transcripts,\n }\n );\n break;\n\n case TRANSCRIPTION_TYPE.TRANSCRIPT_FINAL_RESULT:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.NEW_CAPTION,\n {\n isFinal: true,\n transcriptId: voiceaPayload.transcript_id,\n transcript: {\n csis: voiceaPayload.csis,\n text: voiceaPayload.transcript.text,\n transcriptLanguageCode: voiceaPayload.transcript.transcript_language_code,\n },\n timestamp: millisToMinutesAndSeconds(voiceaPayload.transcript.end_millis),\n }\n );\n break;\n\n case TRANSCRIPTION_TYPE.HIGHLIGHT_CREATED:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.HIGHLIGHT_CREATED,\n {\n csis: voiceaPayload.highlight.csis,\n highlightId: voiceaPayload.highlight.highlight_id,\n text: voiceaPayload.highlight.transcript,\n highlightLabel: voiceaPayload.highlight.highlight_label,\n highlightSource: voiceaPayload.highlight.highlight_source,\n timestamp: millisToMinutesAndSeconds(voiceaPayload.highlight.end_millis),\n }\n );\n break;\n\n case TRANSCRIPTION_TYPE.EVA_THANKS:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.EVA_COMMAND,\n {\n isListening: false,\n text: voiceaPayload.command_response,\n }\n );\n break;\n\n case TRANSCRIPTION_TYPE.EVA_WAKE:\n case TRANSCRIPTION_TYPE.EVA_CANCEL:\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processTranscription',\n },\n EVENT_TRIGGERS.EVA_COMMAND,\n {\n isListening: voiceaPayload.type === TRANSCRIPTION_TYPE.EVA_WAKE,\n }\n );\n break;\n\n default:\n break;\n }\n };\n\n /**\n * Processes Caption Language Response\n * @param {CaptionLanguageResponse} voiceaPayload\n * @returns {void}\n */\n private processCaptionLanguageResponse = (voiceaPayload: CaptionLanguageResponse): void => {\n if (voiceaPayload.statusCode === 200) {\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processCaptionLanguageResponse',\n },\n EVENT_TRIGGERS.CAPTION_LANGUAGE_UPDATE,\n {statusCode: 200}\n );\n } else {\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processCaptionLanguageResponse',\n },\n EVENT_TRIGGERS.CAPTION_LANGUAGE_UPDATE,\n {statusCode: voiceaPayload.errorCode, errorMessage: voiceaPayload.message}\n );\n }\n };\n\n /**\n * processes voicea announcement response and triggers event\n * @param {Object} voiceaPayload\n * @returns {void}\n */\n private processAnnouncementMessage = (voiceaPayload: AnnouncementPayload): void => {\n const voiceaLanguageOptions = {\n captionLanguages: voiceaPayload?.translation?.allowed_languages ?? [],\n maxLanguages: voiceaPayload?.translation?.max_languages ?? 0,\n spokenLanguages: voiceaPayload?.ASR?.spoken_languages ?? [],\n };\n\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'processAnnouncementMessage',\n },\n EVENT_TRIGGERS.VOICEA_ANNOUNCEMENT,\n voiceaLanguageOptions\n );\n };\n\n /**\n * Sends Announcement to add voicea to the meeting\n * @returns {void}\n */\n private sendAnnouncement = (): void => {\n this.announceStatus = ANNOUNCE_STATUS.JOINING;\n this.listenToEvents();\n // @ts-ignore\n this.webex.internal.llm.socket.send({\n id: `${this.seqNum}`,\n type: 'publishRequest',\n recipients: {\n // @ts-ignore\n route: this.webex.internal.llm.getBinding(),\n },\n headers: {},\n data: {\n clientPayload: {\n version: 'v2',\n },\n eventType: 'relay.event',\n relayType: VOICEA_RELAY_TYPES.CLIENT_ANNOUNCEMENT,\n },\n trackingId: `${config.trackingIdPrefix}_${uuid.v4().toString()}`,\n });\n this.seqNum += 1;\n };\n\n /**\n * Set Spoken Language for the meeting\n * @param {string} languageCode\n * @returns {Promise}\n */\n public setSpokenLanguage = (languageCode: string): Promise<void> =>\n // @ts-ignore\n this.request({\n method: 'PUT',\n // @ts-ignore\n url: `${this.webex.internal.llm.getLocusUrl()}/controls/`,\n body: {\n languageCode,\n },\n }).then(() => {\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'setSpokenLanguage',\n },\n EVENT_TRIGGERS.SPOKEN_LANGUAGE_UPDATE,\n {languageCode}\n );\n });\n\n /**\n * Request Language translation\n * @param {string} languageCode\n * @returns {void}\n */\n public requestLanguage = (languageCode: string): void => {\n // @ts-ignore\n if (!this.webex.internal.llm.isConnected()) return;\n // @ts-ignore\n this.webex.internal.llm.socket.send({\n id: `${this.seqNum}`,\n type: 'publishRequest',\n recipients: {\n // @ts-ignore\n route: this.webex.internal.llm.getBinding(),\n },\n headers: {\n to: this.vmcDeviceId,\n },\n data: {\n clientPayload: {\n translationLanguage: languageCode,\n id: uuid.v4(),\n },\n eventType: 'relay.event',\n relayType: VOICEA_RELAY_TYPES.TRANSLATION_REQUEST,\n },\n trackingId: `${config.trackingIdPrefix}_${uuid.v4().toString()}`,\n });\n this.seqNum += 1;\n };\n\n /**\n * request turn on Captions\n * @returns {Promise}\n */\n private requestTurnOnCaptions = (): undefined | Promise<void> => {\n this.captionStatus = TURN_ON_CAPTION_STATUS.SENDING;\n // @ts-ignore\n // eslint-disable-next-line newline-before-return\n return this.request({\n method: 'PUT',\n // @ts-ignore\n url: `${this.webex.internal.llm.getLocusUrl()}/controls/`,\n body: {\n transcribe: {caption: true},\n },\n })\n .then(() => {\n Trigger.trigger(\n this,\n {\n file: 'voicea',\n function: 'turnOnCaptions',\n },\n EVENT_TRIGGERS.CAPTIONS_TURNED_ON\n );\n this.areCaptionsEnabled = true;\n this.captionStatus = TURN_ON_CAPTION_STATUS.ENABLED;\n this.announce();\n })\n .catch(() => {\n this.captionStatus = TURN_ON_CAPTION_STATUS.IDLE;\n throw new Error('turn on captions fail');\n });\n };\n\n /**\n * is announce processing\n * @returns {boolean}\n */\n private isAnnounceProcessing = () =>\n [ANNOUNCE_STATUS.JOINING, ANNOUNCE_STATUS.JOINED].includes(this.announceStatus);\n\n /**\n * announce to voicea data chanel\n * @returns {void}\n */\n public announce = () => {\n if (this.isAnnounceProcessing()) return;\n // @ts-ignore\n if (!this.webex.internal.llm.isConnected()) {\n throw new Error('voicea can not announce before llm connected');\n }\n this.sendAnnouncement();\n };\n\n /**\n * is turn on caption processing\n * @returns {boolean}\n */\n private isCaptionProcessing = () =>\n [TURN_ON_CAPTION_STATUS.SENDING, TURN_ON_CAPTION_STATUS.ENABLED].includes(this.captionStatus);\n\n /**\n * Turn on Captions\n * @returns {Promise}\n */\n public turnOnCaptions = async (): undefined | Promise<void> => {\n if (this.isCaptionProcessing()) return undefined;\n // @ts-ignore\n if (!this.webex.internal.llm.isConnected()) {\n throw new Error('can not turn on captions before llm connected');\n }\n\n return this.requestTurnOnCaptions();\n };\n\n /**\n * Toggle transcribing for highlights\n * @param {bool} activate if true transcribing is turned on\n * @returns {Promise}\n */\n public toggleTranscribing = async (activate: boolean): undefined | Promise<void> => {\n // @ts-ignore\n return this.request({\n method: 'PUT',\n // @ts-ignore\n url: `${this.webex.internal.llm.getLocusUrl()}/controls/`,\n body: {\n transcribe: {transcribing: activate},\n },\n }).then(() => {\n if (activate && !this.areCaptionsEnabled) this.turnOnCaptions();\n });\n };\n\n /**\n * get caption status\n * @returns {string}\n */\n public getCaptionStatus = () => this.captionStatus;\n\n /**\n * get announce status\n * @returns {string}\n */\n public getAnnounceStatus = () => this.announceStatus;\n}\n\nexport default VoiceaChannel;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["voicea.types.ts"],"sourcesContent":["/* eslint-disable camelcase */\n/* eslint-disable no-undef */\n\n/**\n * Type for payload\n */\ninterface AnnouncementPayload {\n translation: {\n max_languages: number;\n allowed_languages: string[];\n };\n\n ASR: {\n spoken_languages: string[];\n };\n}\n\n// eslint-disable-next-line no-undef\ntype TRANSCRIPTION_TYPES =\n | 'unknown'\n | 'eva_wake'\n | 'eva_thanks'\n | 'eva_cancel'\n | 'highlight_created'\n | 'transcript_interim_results'\n | 'transcript_final_result';\n\n/**\n * Class for an Transcription Object\n */\ninterface Transcription {\n start_millis: number;\n end_millis: number;\n text: string;\n transcript_language_code: string;\n translations: {[x: string]: string};\n csis: number[];\n last_packet_timestamp_ms: number;\n}\n\n/**\n * Highlights\n */\ninterface Highlight {\n highlight_id: string;\n transcript: string;\n highlight_label: string;\n highlight_source: string;\n start_millis: number;\n end_millis: number;\n csis: number[];\n}\n/**\n * Type for Transcription message\n */\ninterface TranscriptionResponse {\n type: TRANSCRIPTION_TYPES;\n transcript_id: string;\n translations?: {[x: string]: string};\n transcripts?: Transcription[];\n transcript?: Transcription;\n highlight?: Highlight;\n csis: number[];\n data: string;\n command_response: string;\n}\n/**\n * Type for CaptionLanguageResponse\n */\ninterface CaptionLanguageResponse {\n requestId: string;\n statusCode: number;\n errorCode: number;\n message: string;\n}\n\ninterface IVoiceaChannel {\n setSpokenLanguage: (languageCode: string) => Promise<void>;\n requestLanguage: (languageCode: string) => void;\n turnOnCaptions: () => undefined | Promise<void>;\n toggleTranscribing: (activate: boolean) => undefined | Promise<void>;\n deregisterEvents: () => undefined | Promise<void>;\n}\n\nexport type {\n AnnouncementPayload,\n CaptionLanguageResponse,\n TranscriptionResponse,\n Transcription,\n Highlight,\n IVoiceaChannel,\n};\n"],"mappings":""}
1
+ {"version":3,"names":[],"sources":["voicea.types.ts"],"sourcesContent":["/* eslint-disable camelcase */\n/* eslint-disable no-undef */\n\n/**\n * Type for payload\n */\ninterface AnnouncementPayload {\n translation: {\n max_languages: number;\n allowed_languages: string[];\n };\n\n ASR: {\n spoken_languages: string[];\n };\n}\n\n// eslint-disable-next-line no-undef\ntype TRANSCRIPTION_TYPES =\n | 'unknown'\n | 'eva_wake'\n | 'eva_thanks'\n | 'eva_cancel'\n | 'highlight_created'\n | 'transcript_interim_results'\n | 'transcript_final_result';\n\n/**\n * Class for an Transcription Object\n */\ninterface Transcription {\n start_millis: number;\n end_millis: number;\n text: string;\n transcript_language_code: string;\n translations: {[x: string]: string};\n csis: number[];\n last_packet_timestamp_ms: number;\n}\n\n/**\n * Highlights\n */\ninterface Highlight {\n highlight_id: string;\n transcript: string;\n highlight_label: string;\n highlight_source: string;\n start_millis: number;\n end_millis: number;\n csis: number[];\n}\n/**\n * Type for Transcription message\n */\ninterface TranscriptionResponse {\n type: TRANSCRIPTION_TYPES;\n transcript_id: string;\n translations?: {[x: string]: string};\n transcripts?: Transcription[];\n transcript?: Transcription;\n highlight?: Highlight;\n csis: number[];\n data: string;\n command_response: string;\n}\n/**\n * Type for CaptionLanguageResponse\n */\ninterface CaptionLanguageResponse {\n requestId: string;\n statusCode: number;\n errorCode: number;\n message: string;\n}\n\ninterface IVoiceaChannel {\n setSpokenLanguage: (languageCode: string) => Promise<void>;\n requestLanguage: (languageCode: string) => void;\n turnOnCaptions: () => undefined | Promise<void>;\n toggleTranscribing: (activate: boolean) => undefined | Promise<void>;\n deregisterEvents: () => void;\n}\n\nexport type {\n AnnouncementPayload,\n CaptionLanguageResponse,\n TranscriptionResponse,\n Transcription,\n Highlight,\n IVoiceaChannel,\n};\n"],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/internal-plugin-voicea",
3
- "version": "3.0.0-beta.39",
3
+ "version": "3.0.0-beta.391",
4
4
  "description": "",
5
5
  "license": "Cisco EULA (https://www.cisco.com/c/en/us/products/end-user-license-agreement.html)",
6
6
  "main": "dist/index.js",
@@ -14,11 +14,11 @@
14
14
  "node": ">=16"
15
15
  },
16
16
  "dependencies": {
17
- "@webex/internal-plugin-llm": "3.0.0-beta.39",
18
- "@webex/internal-plugin-mercury": "3.0.0-beta.39",
19
- "@webex/internal-plugin-voicea": "3.0.0-beta.39",
20
- "@webex/plugin-meetings": "3.0.0-beta.39",
21
- "@webex/webex-core": "3.0.0-beta.39",
17
+ "@webex/internal-plugin-llm": "3.0.0-beta.391",
18
+ "@webex/internal-plugin-mercury": "3.0.0-beta.391",
19
+ "@webex/internal-plugin-voicea": "3.0.0-beta.391",
20
+ "@webex/plugin-meetings": "3.0.0-beta.391",
21
+ "@webex/webex-core": "3.0.0-beta.391",
22
22
  "uuid": "^3.3.2"
23
23
  },
24
24
  "browserify": {
@@ -28,9 +28,9 @@
28
28
  ]
29
29
  },
30
30
  "devDependencies": {
31
- "@webex/test-helper-chai": "3.0.0-beta.39",
32
- "@webex/test-helper-mock-web-socket": "3.0.0-beta.39",
33
- "@webex/test-helper-mock-webex": "3.0.0-beta.39",
31
+ "@webex/test-helper-chai": "3.0.0-beta.391",
32
+ "@webex/test-helper-mock-web-socket": "3.0.0-beta.391",
33
+ "@webex/test-helper-mock-webex": "3.0.0-beta.391",
34
34
  "sinon": "^9.2.4"
35
35
  }
36
36
  }
package/src/constants.ts CHANGED
@@ -30,3 +30,15 @@ export const TRANSCRIPTION_TYPE = {
30
30
  };
31
31
 
32
32
  export const VOICEA = 'voicea';
33
+
34
+ export const ANNOUNCE_STATUS = {
35
+ IDLE: 'idle',
36
+ JOINED: 'joined',
37
+ JOINING: 'joining',
38
+ };
39
+
40
+ export const TURN_ON_CAPTION_STATUS = {
41
+ IDLE: 'idle',
42
+ ENABLED: 'enabled',
43
+ SENDING: 'sending',
44
+ };
package/src/voicea.ts CHANGED
@@ -2,7 +2,14 @@ import uuid from 'uuid';
2
2
  import {TriggerProxy as Trigger} from '@webex/plugin-meetings';
3
3
  import {WebexPlugin, config} from '@webex/webex-core';
4
4
 
5
- import {EVENT_TRIGGERS, VOICEA_RELAY_TYPES, TRANSCRIPTION_TYPE, VOICEA} from './constants';
5
+ import {
6
+ EVENT_TRIGGERS,
7
+ VOICEA_RELAY_TYPES,
8
+ TRANSCRIPTION_TYPE,
9
+ VOICEA,
10
+ ANNOUNCE_STATUS,
11
+ TURN_ON_CAPTION_STATUS,
12
+ } from './constants';
6
13
  // eslint-disable-next-line no-unused-vars
7
14
  import {
8
15
  AnnouncementPayload,
@@ -22,14 +29,16 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
22
29
 
23
30
  private seqNum: number;
24
31
 
25
- private hasVoiceaJoined: boolean;
26
-
27
32
  private areCaptionsEnabled: boolean;
28
33
 
29
34
  private hasSubscribedToEvents = false;
30
35
 
31
36
  private vmcDeviceId?: string;
32
37
 
38
+ private announceStatus: string;
39
+
40
+ private captionStatus: string;
41
+
33
42
  /**
34
43
  * @param {Object} e
35
44
  * @returns {undefined}
@@ -40,7 +49,7 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
40
49
  switch (e.data.relayType) {
41
50
  case VOICEA_RELAY_TYPES.ANNOUNCEMENT:
42
51
  this.vmcDeviceId = e.headers.from;
43
- this.hasVoiceaJoined = true;
52
+ this.announceStatus = ANNOUNCE_STATUS.JOINED;
44
53
  this.processAnnouncementMessage(e.data.voiceaPayload);
45
54
  break;
46
55
  case VOICEA_RELAY_TYPES.TRANSLATION_RESPONSE:
@@ -66,14 +75,18 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
66
75
  }
67
76
  }
68
77
 
69
- // @ts-ignore
78
+ /**
79
+ * Listen to websocket messages
80
+ * @returns {void}
81
+ */
70
82
  public deregisterEvents() {
71
- this.hasVoiceaJoined = false;
72
83
  this.areCaptionsEnabled = false;
73
84
  this.vmcDeviceId = undefined;
74
85
  // @ts-ignore
75
86
  this.webex.internal.llm.off('event:relay.event', this.eventProcessor);
76
87
  this.hasSubscribedToEvents = false;
88
+ this.announceStatus = ANNOUNCE_STATUS.IDLE;
89
+ this.captionStatus = TURN_ON_CAPTION_STATUS.IDLE;
77
90
  }
78
91
 
79
92
  /**
@@ -83,9 +96,10 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
83
96
  constructor(...args) {
84
97
  super(...args);
85
98
  this.seqNum = 1;
86
- this.hasVoiceaJoined = false;
87
99
  this.areCaptionsEnabled = false;
88
100
  this.vmcDeviceId = undefined;
101
+ this.announceStatus = ANNOUNCE_STATUS.IDLE;
102
+ this.captionStatus = TURN_ON_CAPTION_STATUS.IDLE;
89
103
  }
90
104
 
91
105
  /**
@@ -243,9 +257,7 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
243
257
  * @returns {void}
244
258
  */
245
259
  private sendAnnouncement = (): void => {
246
- // @ts-ignore
247
- if (this.hasVoiceaJoined || !this.webex.internal.llm.isConnected()) return;
248
-
260
+ this.announceStatus = ANNOUNCE_STATUS.JOINING;
249
261
  this.listenToEvents();
250
262
  // @ts-ignore
251
263
  this.webex.internal.llm.socket.send({
@@ -327,11 +339,11 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
327
339
  };
328
340
 
329
341
  /**
330
- * Turn on Captions
342
+ * request turn on Captions
331
343
  * @returns {Promise}
332
344
  */
333
- public turnOnCaptions = async (): undefined | Promise<void> => {
334
- if (this.hasVoiceaJoined && this.areCaptionsEnabled) return undefined;
345
+ private requestTurnOnCaptions = (): undefined | Promise<void> => {
346
+ this.captionStatus = TURN_ON_CAPTION_STATUS.SENDING;
335
347
  // @ts-ignore
336
348
  // eslint-disable-next-line newline-before-return
337
349
  return this.request({
@@ -341,18 +353,65 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
341
353
  body: {
342
354
  transcribe: {caption: true},
343
355
  },
344
- }).then(() => {
345
- Trigger.trigger(
346
- this,
347
- {
348
- file: 'voicea',
349
- function: 'turnOnCaptions',
350
- },
351
- EVENT_TRIGGERS.CAPTIONS_TURNED_ON
352
- );
353
- this.areCaptionsEnabled = true;
354
- this.sendAnnouncement();
355
- });
356
+ })
357
+ .then(() => {
358
+ Trigger.trigger(
359
+ this,
360
+ {
361
+ file: 'voicea',
362
+ function: 'turnOnCaptions',
363
+ },
364
+ EVENT_TRIGGERS.CAPTIONS_TURNED_ON
365
+ );
366
+ this.areCaptionsEnabled = true;
367
+ this.captionStatus = TURN_ON_CAPTION_STATUS.ENABLED;
368
+ this.announce();
369
+ })
370
+ .catch(() => {
371
+ this.captionStatus = TURN_ON_CAPTION_STATUS.IDLE;
372
+ throw new Error('turn on captions fail');
373
+ });
374
+ };
375
+
376
+ /**
377
+ * is announce processing
378
+ * @returns {boolean}
379
+ */
380
+ private isAnnounceProcessing = () =>
381
+ [ANNOUNCE_STATUS.JOINING, ANNOUNCE_STATUS.JOINED].includes(this.announceStatus);
382
+
383
+ /**
384
+ * announce to voicea data chanel
385
+ * @returns {void}
386
+ */
387
+ public announce = () => {
388
+ if (this.isAnnounceProcessing()) return;
389
+ // @ts-ignore
390
+ if (!this.webex.internal.llm.isConnected()) {
391
+ throw new Error('voicea can not announce before llm connected');
392
+ }
393
+ this.sendAnnouncement();
394
+ };
395
+
396
+ /**
397
+ * is turn on caption processing
398
+ * @returns {boolean}
399
+ */
400
+ private isCaptionProcessing = () =>
401
+ [TURN_ON_CAPTION_STATUS.SENDING, TURN_ON_CAPTION_STATUS.ENABLED].includes(this.captionStatus);
402
+
403
+ /**
404
+ * Turn on Captions
405
+ * @returns {Promise}
406
+ */
407
+ public turnOnCaptions = async (): undefined | Promise<void> => {
408
+ if (this.isCaptionProcessing()) return undefined;
409
+ // @ts-ignore
410
+ if (!this.webex.internal.llm.isConnected()) {
411
+ throw new Error('can not turn on captions before llm connected');
412
+ }
413
+
414
+ return this.requestTurnOnCaptions();
356
415
  };
357
416
 
358
417
  /**
@@ -370,9 +429,21 @@ export class VoiceaChannel extends WebexPlugin implements IVoiceaChannel {
370
429
  transcribe: {transcribing: activate},
371
430
  },
372
431
  }).then(() => {
373
- if (activate && !this.areCaptionsEnabled && !this.hasVoiceaJoined) this.turnOnCaptions();
432
+ if (activate && !this.areCaptionsEnabled) this.turnOnCaptions();
374
433
  });
375
434
  };
435
+
436
+ /**
437
+ * get caption status
438
+ * @returns {string}
439
+ */
440
+ public getCaptionStatus = () => this.captionStatus;
441
+
442
+ /**
443
+ * get announce status
444
+ * @returns {string}
445
+ */
446
+ public getAnnounceStatus = () => this.announceStatus;
376
447
  }
377
448
 
378
449
  export default VoiceaChannel;
@@ -79,7 +79,7 @@ interface IVoiceaChannel {
79
79
  requestLanguage: (languageCode: string) => void;
80
80
  turnOnCaptions: () => undefined | Promise<void>;
81
81
  toggleTranscribing: (activate: boolean) => undefined | Promise<void>;
82
- deregisterEvents: () => undefined | Promise<void>;
82
+ deregisterEvents: () => void;
83
83
  }
84
84
 
85
85
  export type {
@@ -1,6 +1,7 @@
1
+ import 'jsdom-global/register';
1
2
  import MockWebex from '@webex/test-helper-mock-webex';
2
3
  import MockWebSocket from '@webex/test-helper-mock-web-socket';
3
- import {assert} from '@webex/test-helper-chai';
4
+ import {assert, expect} from '@webex/test-helper-chai';
4
5
  import sinon from 'sinon';
5
6
  import Mercury from '@webex/internal-plugin-mercury';
6
7
  import LLMChannel from '@webex/internal-plugin-llm';
@@ -41,17 +42,26 @@ describe('plugin-voicea', () => {
41
42
  });
42
43
  });
43
44
 
45
+ describe("#constructor", () => {
46
+ it('should init status', () => {
47
+ assert.equal(voiceaService.announceStatus, 'idle');
48
+ assert.equal(voiceaService.captionStatus, 'idle');
49
+ });
50
+ });
51
+
44
52
  describe('#sendAnnouncement', () => {
45
53
  beforeEach(async () => {
46
54
  const mockWebSocket = new MockWebSocket();
47
55
 
48
56
  voiceaService.webex.internal.llm.socket = mockWebSocket;
57
+ voiceaService.announceStatus = "idle";
49
58
  });
50
59
 
51
60
  it("sends announcement if voicea hasn't joined", () => {
52
61
  const spy = sinon.spy(voiceaService, 'listenToEvents');
53
62
 
54
63
  voiceaService.sendAnnouncement();
64
+ assert.equal(voiceaService.announceStatus, 'joining');
55
65
  assert.calledOnce(spy);
56
66
 
57
67
  assert.calledOnceWithExactly(voiceaService.webex.internal.llm.socket.send, {
@@ -98,14 +108,14 @@ describe('plugin-voicea', () => {
98
108
  data: {relayType: 'voicea.annc', voiceaPayload: {}},
99
109
  });
100
110
 
101
- assert.equal(voiceaService.hasVoiceaJoined, true);
102
111
  assert.equal(voiceaService.areCaptionsEnabled, true);
103
112
  assert.equal(voiceaService.vmcDeviceId, 'ws');
104
113
 
105
114
  voiceaService.deregisterEvents();
106
- assert.equal(voiceaService.hasVoiceaJoined, false);
107
115
  assert.equal(voiceaService.areCaptionsEnabled, false);
108
116
  assert.equal(voiceaService.vmcDeviceId, undefined);
117
+ assert.equal(voiceaService.announceStatus, 'idle');
118
+ assert.equal(voiceaService.captionStatus, 'idle');
109
119
  });
110
120
  });
111
121
  describe('#processAnnouncementMessage', () => {
@@ -198,22 +208,28 @@ describe('plugin-voicea', () => {
198
208
  });
199
209
  });
200
210
 
201
- describe('#turnOnCaptions', () => {
211
+ describe('#requestTurnOnCaptions', () => {
202
212
  beforeEach(async () => {
203
213
  const mockWebSocket = new MockWebSocket();
204
214
 
205
215
  voiceaService.webex.internal.llm.socket = mockWebSocket;
216
+ voiceaService.captionStatus = 'idle';
206
217
  });
207
218
 
219
+ afterEach( () => {
220
+ voiceaService.captionStatus = 'idle';
221
+ })
222
+
208
223
  it('turns on captions', async () => {
209
- const announcementSpy = sinon.spy(voiceaService, 'sendAnnouncement');
224
+ const announcementSpy = sinon.spy(voiceaService, 'announce');
210
225
 
211
226
  const triggerSpy = sinon.spy();
212
227
 
213
228
  voiceaService.on(EVENT_TRIGGERS.CAPTIONS_TURNED_ON, triggerSpy);
214
229
  voiceaService.listenToEvents();
215
230
 
216
- await voiceaService.turnOnCaptions();
231
+ await voiceaService.requestTurnOnCaptions();
232
+ assert.equal(voiceaService.captionStatus, 'enabled');
217
233
  sinon.assert.calledWith(
218
234
  voiceaService.request,
219
235
  sinon.match({
@@ -228,18 +244,119 @@ describe('plugin-voicea', () => {
228
244
  assert.calledOnce(announcementSpy);
229
245
  });
230
246
 
231
- it("doesn't call API on captions", async () => {
232
- await voiceaService.turnOnCaptions();
247
+ it("should handle request fail", async () => {
248
+ voiceaService.captionStatus = 'sending';
249
+ voiceaService.request = sinon.stub().rejects();
250
+
251
+ try {
252
+ await voiceaService.requestTurnOnCaptions();
253
+ } catch (error) {
254
+ expect(error.message).to.include('turn on captions fail');
255
+ return;
256
+ }
257
+ assert.equal(voiceaService.captionStatus, 'idle');
258
+ });
259
+ });
233
260
 
234
- // eslint-disable-next-line no-underscore-dangle
235
- voiceaService.webex.internal.llm._emit('event:relay.event', {
236
- headers: {from: 'ws'},
237
- data: {relayType: 'voicea.annc', voiceaPayload: {}},
261
+ describe("#isAnnounceProcessing", () => {
262
+ afterEach(() => {
263
+ voiceaService.announceStatus = 'idle';
264
+ });
265
+
266
+ ['joining', 'joined'].forEach((status) => {
267
+ it(`should return true when status is ${status}`, () => {
268
+ voiceaService.announceStatus = status;
269
+ assert.equal(voiceaService.isAnnounceProcessing(), true);
270
+ });
271
+ });
272
+
273
+ it('should return false when status is not processing status', () => {
274
+ voiceaService.announceStatus = 'idle';
275
+ assert.equal(voiceaService.isAnnounceProcessing(), false);
276
+ });
277
+ });
278
+
279
+ describe("#announce", () => {
280
+ let isAnnounceProcessing, sendAnnouncement;
281
+ beforeEach(() => {
282
+ voiceaService.webex.internal.llm.isConnected.returns(true);
283
+ sendAnnouncement = sinon.stub(voiceaService, 'sendAnnouncement');
284
+ isAnnounceProcessing = sinon.stub(voiceaService, 'isAnnounceProcessing').returns(false)
285
+ });
286
+
287
+ afterEach(() => {
288
+ voiceaService.webex.internal.llm.isConnected.returns(true);
289
+ isAnnounceProcessing.restore();
290
+ sendAnnouncement.restore();
291
+ });
292
+
293
+ it('announce to llm data channel', ()=> {
294
+ voiceaService.announce();
295
+ assert.calledOnce(sendAnnouncement);
296
+ });
297
+
298
+ it('announce to llm data channel before llm connected', ()=> {
299
+ voiceaService.webex.internal.llm.isConnected.returns(false);
300
+ assert.throws(() => voiceaService.announce(), "voicea can not announce before llm connected");
301
+ assert.notCalled(sendAnnouncement);
302
+ });
303
+
304
+ it('should not announce duplicate', () => {
305
+ isAnnounceProcessing.returns(true);
306
+ voiceaService.announce();
307
+ assert.notCalled(sendAnnouncement);
308
+ })
309
+ });
310
+
311
+ describe("#isCaptionProcessing", () => {
312
+ afterEach(() => {
313
+ voiceaService.captionStatus = 'idle';
314
+ });
315
+
316
+ ['sending', 'enabled'].forEach((status) => {
317
+ it(`should return true when status is ${status}`, () => {
318
+ voiceaService.captionStatus = status;
319
+ assert.equal(voiceaService.isCaptionProcessing(), true);
238
320
  });
321
+ });
239
322
 
240
- const response = await voiceaService.turnOnCaptions();
323
+ it('should return false when status is not processing status', () => {
324
+ voiceaService.captionStatus = 'idle';
325
+ assert.equal(voiceaService.isCaptionProcessing(), false);
326
+ });
327
+ });
241
328
 
242
- assert.equal(response, undefined);
329
+ describe('#turnOnCaptions', () => {
330
+ let requestTurnOnCaptions, isCaptionProcessing;
331
+ beforeEach(() => {
332
+ requestTurnOnCaptions = sinon.stub(voiceaService, 'requestTurnOnCaptions');
333
+ isCaptionProcessing = sinon.stub(voiceaService, 'isCaptionProcessing').returns(false);
334
+ voiceaService.webex.internal.llm.isConnected.returns(true);
335
+ });
336
+
337
+ afterEach(() => {
338
+ requestTurnOnCaptions.restore();
339
+ isCaptionProcessing.restore();
340
+ voiceaService.webex.internal.llm.isConnected.returns(true);
341
+ });
342
+
343
+ it('call request turn on captions', () => {
344
+ isCaptionProcessing.returns(false);
345
+ voiceaService.turnOnCaptions();
346
+ assert.calledOnce(requestTurnOnCaptions);
347
+ });
348
+
349
+ it("turns on captions before llm connected", () => {
350
+ isCaptionProcessing.returns(false);
351
+ voiceaService.webex.internal.llm.isConnected.returns(true);
352
+ // assert.throws(() => voiceaService.turnOnCaptions(), "can not turn on captions before llm connected");
353
+ assert.notCalled(requestTurnOnCaptions);
354
+ });
355
+
356
+ it('should not turn on duplicate when processing', () => {
357
+ isCaptionProcessing.returns(true);
358
+ voiceaService.turnOnCaptions();
359
+ assert.notCalled(voiceaService.requestTurnOnCaptions);
243
360
  });
244
361
  });
245
362
 
@@ -613,5 +730,19 @@ describe('plugin-voicea', () => {
613
730
  });
614
731
  });
615
732
  });
733
+
734
+ describe("#getCaptionStatus", () => {
735
+ it('works correctly', () => {
736
+ voiceaService.captionStatus = "enabled"
737
+ assert.equal(voiceaService.getCaptionStatus(), "enabled");
738
+ });
739
+ });
740
+
741
+ describe("#getAnnounceStatus", () => {
742
+ it('works correctly', () => {
743
+ voiceaService.announceStatus = "joined"
744
+ assert.equal(voiceaService.getAnnounceStatus(), "joined");
745
+ });
746
+ });
616
747
  });
617
748
  });