@webex/internal-plugin-voicea 3.12.0-llmrefactor.7 → 3.12.0-llmrefactor.9
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/types/voicea-plugin.d.ts +3 -3
- package/dist/types/voicea.d.ts +45 -7
- package/dist/voicea-plugin.js +2 -2
- package/dist/voicea-plugin.js.map +1 -1
- package/dist/voicea.js +157 -70
- package/dist/voicea.js.map +1 -1
- package/package.json +4 -4
- package/src/voicea-plugin.ts +3 -3
- package/src/voicea.ts +142 -50
- package/test/unit/spec/voicea-plugin.js +12 -0
- package/test/unit/spec/voicea.js +238 -4
|
@@ -9,15 +9,15 @@ import { VoiceaChannel } from './voicea';
|
|
|
9
9
|
export declare class VoiceaPlugin extends WebexPlugin {
|
|
10
10
|
namespace: string;
|
|
11
11
|
/**
|
|
12
|
-
* Creates a VoiceaChannel bound to
|
|
12
|
+
* Creates a VoiceaChannel, optionally bound to an LLMChannel.
|
|
13
13
|
*
|
|
14
14
|
* Note: VoiceaChannel does not take ownership of the LLMChannel.
|
|
15
15
|
* The caller retains ownership and is responsible for the LLMChannel's
|
|
16
16
|
* lifecycle (connection, disconnection, cleanup).
|
|
17
17
|
*
|
|
18
|
-
* @param {LLMChannel} llmChannel - The LLM channel to use for voicea
|
|
18
|
+
* @param {LLMChannel} [llmChannel] - The LLM channel to use for voicea (optional)
|
|
19
19
|
* @returns {VoiceaChannel} A new VoiceaChannel instance
|
|
20
20
|
*/
|
|
21
|
-
createChannel(llmChannel
|
|
21
|
+
createChannel(llmChannel?: LLMChannel): VoiceaChannel;
|
|
22
22
|
}
|
|
23
23
|
export default VoiceaPlugin;
|
package/dist/types/voicea.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { IVoiceaChannel } from './voicea.types';
|
|
|
11
11
|
*/
|
|
12
12
|
export declare class VoiceaChannel extends EventEmitter implements IVoiceaChannel {
|
|
13
13
|
private request;
|
|
14
|
-
private llmChannel
|
|
14
|
+
private llmChannel?;
|
|
15
15
|
private seqNum;
|
|
16
16
|
private areCaptionsEnabled;
|
|
17
17
|
private hasSubscribedToEvents;
|
|
@@ -23,16 +23,27 @@ export declare class VoiceaChannel extends EventEmitter implements IVoiceaChanne
|
|
|
23
23
|
private currentSpokenLanguage?;
|
|
24
24
|
private spokenLanguages;
|
|
25
25
|
private currentCaptionLanguage?;
|
|
26
|
+
private targetLLMChannel?;
|
|
27
|
+
private _pendingOnlineListener?;
|
|
28
|
+
private _pendingCaptionRestore;
|
|
26
29
|
/**
|
|
27
|
-
* Creates a VoiceaChannel bound to
|
|
28
|
-
*
|
|
30
|
+
* Creates a VoiceaChannel, optionally bound to an LLMChannel.
|
|
31
|
+
* If no llmChannel is provided, call switchLLMChannel() later to attach one.
|
|
32
|
+
* @param {LLMChannel} [llmChannel] - The LLM channel to use (optional)
|
|
29
33
|
* @param {Function} request - The request function for making API calls (typically webex.request bound to webex)
|
|
30
34
|
*/
|
|
31
|
-
constructor(llmChannel: LLMChannel, request: (options: {
|
|
35
|
+
constructor(llmChannel: LLMChannel | undefined, request: (options: {
|
|
32
36
|
method: string;
|
|
33
37
|
url: string;
|
|
34
38
|
body?: object;
|
|
35
39
|
}) => Promise<any>);
|
|
40
|
+
/**
|
|
41
|
+
* Returns the LLM channel, throwing if not available.
|
|
42
|
+
* @private
|
|
43
|
+
* @returns {LLMChannel}
|
|
44
|
+
* @throws {Error} If LLM channel is not available
|
|
45
|
+
*/
|
|
46
|
+
private requireLLMChannel;
|
|
36
47
|
/**
|
|
37
48
|
* Process events from LLM channel
|
|
38
49
|
* @param {Object} e - Event data
|
|
@@ -44,12 +55,39 @@ export declare class VoiceaChannel extends EventEmitter implements IVoiceaChanne
|
|
|
44
55
|
* @returns {void}
|
|
45
56
|
*/
|
|
46
57
|
deregisterEvents(): void;
|
|
58
|
+
/**
|
|
59
|
+
* Attach a pending 'online' listener to a channel for deferred reconciliation.
|
|
60
|
+
* Detaches any existing listener first.
|
|
61
|
+
* @param {LLMChannel} channel - The channel to attach to
|
|
62
|
+
* @param {Function} callback - The callback to run when 'online' fires
|
|
63
|
+
* @private
|
|
64
|
+
* @returns {void}
|
|
65
|
+
*/
|
|
66
|
+
private attachPendingOnline;
|
|
67
|
+
/**
|
|
68
|
+
* Detach any pending 'online' listener.
|
|
69
|
+
* @private
|
|
70
|
+
* @returns {void}
|
|
71
|
+
*/
|
|
72
|
+
private detachPendingOnline;
|
|
73
|
+
/**
|
|
74
|
+
* Reset announcement state for a new connection.
|
|
75
|
+
* @private
|
|
76
|
+
* @returns {void}
|
|
77
|
+
*/
|
|
78
|
+
private resetAnnounceState;
|
|
79
|
+
/**
|
|
80
|
+
* Reconcile voicea binding and caption state to match the desired target.
|
|
81
|
+
* This is idempotent - always re-reads targetLLMChannel and current state.
|
|
82
|
+
* A deferred 'online' callback that fires late self-corrects automatically.
|
|
83
|
+
* @private
|
|
84
|
+
* @returns {Promise<void>}
|
|
85
|
+
*/
|
|
86
|
+
private reconcile;
|
|
47
87
|
/**
|
|
48
88
|
* Switch to a different LLM channel while preserving caption state.
|
|
49
89
|
* Used when transitioning between main meeting and practice session.
|
|
50
|
-
* -
|
|
51
|
-
* - Unsubscribes from old channel, subscribes to new channel
|
|
52
|
-
* - Re-announces and re-enables captions if they were on
|
|
90
|
+
* This is a thin intent-setter - actual binding happens in reconcile().
|
|
53
91
|
* @param {LLMChannel} newLLMChannel - The new LLM channel to switch to
|
|
54
92
|
* @returns {Promise<void>}
|
|
55
93
|
*/
|
package/dist/voicea-plugin.js
CHANGED
|
@@ -39,13 +39,13 @@ var VoiceaPlugin = exports.VoiceaPlugin = /*#__PURE__*/function (_WebexPlugin) {
|
|
|
39
39
|
key: "createChannel",
|
|
40
40
|
value:
|
|
41
41
|
/**
|
|
42
|
-
* Creates a VoiceaChannel bound to
|
|
42
|
+
* Creates a VoiceaChannel, optionally bound to an LLMChannel.
|
|
43
43
|
*
|
|
44
44
|
* Note: VoiceaChannel does not take ownership of the LLMChannel.
|
|
45
45
|
* The caller retains ownership and is responsible for the LLMChannel's
|
|
46
46
|
* lifecycle (connection, disconnection, cleanup).
|
|
47
47
|
*
|
|
48
|
-
* @param {LLMChannel} llmChannel - The LLM channel to use for voicea
|
|
48
|
+
* @param {LLMChannel} [llmChannel] - The LLM channel to use for voicea (optional)
|
|
49
49
|
* @returns {VoiceaChannel} A new VoiceaChannel instance
|
|
50
50
|
*/
|
|
51
51
|
function createChannel(llmChannel) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_webexCore","require","_voicea","_constants","_callSuper","t","o","e","_getPrototypeOf2","default","_possibleConstructorReturn2","_isNativeReflectConstruct","_Reflect$construct","constructor","apply","Boolean","prototype","valueOf","call","VoiceaPlugin","exports","_WebexPlugin","_this","_classCallCheck2","_len","arguments","length","args","Array","_key","concat","_defineProperty2","VOICEA","_inherits2","_createClass2","key","value","createChannel","llmChannel","channel","VoiceaChannel","webex","request","bind","WebexPlugin","_default"],"sources":["voicea-plugin.ts"],"sourcesContent":["import {WebexPlugin} from '@webex/webex-core';\nimport type LLMChannel from '@webex/internal-plugin-llm';\n\nimport {VoiceaChannel} from './voicea';\nimport {VOICEA} from './constants';\n\n/**\n * VoiceaPlugin - factory for creating VoiceaChannel instances\n * @export\n * @class VoiceaPlugin\n */\nexport class VoiceaPlugin extends WebexPlugin {\n namespace = VOICEA;\n\n /**\n * Creates a VoiceaChannel bound to
|
|
1
|
+
{"version":3,"names":["_webexCore","require","_voicea","_constants","_callSuper","t","o","e","_getPrototypeOf2","default","_possibleConstructorReturn2","_isNativeReflectConstruct","_Reflect$construct","constructor","apply","Boolean","prototype","valueOf","call","VoiceaPlugin","exports","_WebexPlugin","_this","_classCallCheck2","_len","arguments","length","args","Array","_key","concat","_defineProperty2","VOICEA","_inherits2","_createClass2","key","value","createChannel","llmChannel","channel","VoiceaChannel","webex","request","bind","WebexPlugin","_default"],"sources":["voicea-plugin.ts"],"sourcesContent":["import {WebexPlugin} from '@webex/webex-core';\nimport type LLMChannel from '@webex/internal-plugin-llm';\n\nimport {VoiceaChannel} from './voicea';\nimport {VOICEA} from './constants';\n\n/**\n * VoiceaPlugin - factory for creating VoiceaChannel instances\n * @export\n * @class VoiceaPlugin\n */\nexport class VoiceaPlugin extends WebexPlugin {\n namespace = VOICEA;\n\n /**\n * Creates a VoiceaChannel, optionally bound to an LLMChannel.\n *\n * Note: VoiceaChannel does not take ownership of the LLMChannel.\n * The caller retains ownership and is responsible for the LLMChannel's\n * lifecycle (connection, disconnection, cleanup).\n *\n * @param {LLMChannel} [llmChannel] - The LLM channel to use for voicea (optional)\n * @returns {VoiceaChannel} A new VoiceaChannel instance\n */\n public createChannel(llmChannel?: LLMChannel): VoiceaChannel {\n // @ts-ignore - webex is available on WebexPlugin\n const channel = new VoiceaChannel(llmChannel, this.webex.request.bind(this.webex));\n\n return channel;\n }\n}\n\nexport default VoiceaPlugin;\n"],"mappings":";;;;;;;;;;;;;;;AAAA,IAAAA,UAAA,GAAAC,OAAA;AAGA,IAAAC,OAAA,GAAAD,OAAA;AACA,IAAAE,UAAA,GAAAF,OAAA;AAAmC,SAAAG,WAAAC,CAAA,EAAAC,CAAA,EAAAC,CAAA,WAAAD,CAAA,OAAAE,gBAAA,CAAAC,OAAA,EAAAH,CAAA,OAAAI,2BAAA,CAAAD,OAAA,EAAAJ,CAAA,EAAAM,yBAAA,KAAAC,kBAAA,CAAAN,CAAA,EAAAC,CAAA,YAAAC,gBAAA,CAAAC,OAAA,EAAAJ,CAAA,EAAAQ,WAAA,IAAAP,CAAA,CAAAQ,KAAA,CAAAT,CAAA,EAAAE,CAAA;AAAA,SAAAI,0BAAA,cAAAN,CAAA,IAAAU,OAAA,CAAAC,SAAA,CAAAC,OAAA,CAAAC,IAAA,CAAAN,kBAAA,CAAAG,OAAA,iCAAAV,CAAA,aAAAM,yBAAA,YAAAA,0BAAA,aAAAN,CAAA;AAEnC;AACA;AACA;AACA;AACA;AAJA,IAKac,YAAY,GAAAC,OAAA,CAAAD,YAAA,0BAAAE,YAAA;EAAA,SAAAF,aAAA;IAAA,IAAAG,KAAA;IAAA,IAAAC,gBAAA,CAAAd,OAAA,QAAAU,YAAA;IAAA,SAAAK,IAAA,GAAAC,SAAA,CAAAC,MAAA,EAAAC,IAAA,OAAAC,KAAA,CAAAJ,IAAA,GAAAK,IAAA,MAAAA,IAAA,GAAAL,IAAA,EAAAK,IAAA;MAAAF,IAAA,CAAAE,IAAA,IAAAJ,SAAA,CAAAI,IAAA;IAAA;IAAAP,KAAA,GAAAlB,UAAA,OAAAe,YAAA,KAAAW,MAAA,CAAAH,IAAA;IAAA,IAAAI,gBAAA,CAAAtB,OAAA,EAAAa,KAAA,eACXU,iBAAM;IAAA,OAAAV,KAAA;EAAA;EAAA,IAAAW,UAAA,CAAAxB,OAAA,EAAAU,YAAA,EAAAE,YAAA;EAAA,WAAAa,aAAA,CAAAzB,OAAA,EAAAU,YAAA;IAAAgB,GAAA;IAAAC,KAAA;IAElB;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;IACE,SAAOC,aAAaA,CAACC,UAAuB,EAAiB;MAC3D;MACA,IAAMC,OAAO,GAAG,IAAIC,qBAAa,CAACF,UAAU,EAAE,IAAI,CAACG,KAAK,CAACC,OAAO,CAACC,IAAI,CAAC,IAAI,CAACF,KAAK,CAAC,CAAC;MAElF,OAAOF,OAAO;IAChB;EAAC;AAAA,EAlB+BK,sBAAW;AAAA,IAAAC,QAAA,GAAAzB,OAAA,CAAAX,OAAA,GAqB9BU,YAAY","ignoreList":[]}
|
package/dist/voicea.js
CHANGED
|
@@ -12,6 +12,7 @@ _Object$defineProperty(exports, "__esModule", {
|
|
|
12
12
|
value: true
|
|
13
13
|
});
|
|
14
14
|
exports.default = exports.VoiceaChannel = void 0;
|
|
15
|
+
var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));
|
|
15
16
|
var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs2/regenerator"));
|
|
16
17
|
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/asyncToGenerator"));
|
|
17
18
|
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/classCallCheck"));
|
|
@@ -39,8 +40,9 @@ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.
|
|
|
39
40
|
*/
|
|
40
41
|
var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter) {
|
|
41
42
|
/**
|
|
42
|
-
* Creates a VoiceaChannel bound to
|
|
43
|
-
*
|
|
43
|
+
* Creates a VoiceaChannel, optionally bound to an LLMChannel.
|
|
44
|
+
* If no llmChannel is provided, call switchLLMChannel() later to attach one.
|
|
45
|
+
* @param {LLMChannel} [llmChannel] - The LLM channel to use (optional)
|
|
44
46
|
* @param {Function} request - The request function for making API calls (typically webex.request bound to webex)
|
|
45
47
|
*/
|
|
46
48
|
function VoiceaChannel(llmChannel, request) {
|
|
@@ -60,6 +62,12 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
60
62
|
(0, _defineProperty2.default)(_this, "currentSpokenLanguage", void 0);
|
|
61
63
|
(0, _defineProperty2.default)(_this, "spokenLanguages", []);
|
|
62
64
|
(0, _defineProperty2.default)(_this, "currentCaptionLanguage", void 0);
|
|
65
|
+
// Target channel for reconciler pattern - the channel voicea WANTS to be bound to
|
|
66
|
+
(0, _defineProperty2.default)(_this, "targetLLMChannel", void 0);
|
|
67
|
+
// Single pending 'online' listener for deferred reconciliation
|
|
68
|
+
(0, _defineProperty2.default)(_this, "_pendingOnlineListener", void 0);
|
|
69
|
+
// Tracks whether caption restoration is pending (set on switch, cleared on restore)
|
|
70
|
+
(0, _defineProperty2.default)(_this, "_pendingCaptionRestore", false);
|
|
63
71
|
/**
|
|
64
72
|
* Process events from LLM channel
|
|
65
73
|
* @param {Object} e - Event data
|
|
@@ -218,7 +226,8 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
218
226
|
* @returns {boolean}
|
|
219
227
|
*/
|
|
220
228
|
(0, _defineProperty2.default)(_this, "isLLMConnected", function () {
|
|
221
|
-
|
|
229
|
+
var _this$llmChannel$isCo, _this$llmChannel;
|
|
230
|
+
return (_this$llmChannel$isCo = (_this$llmChannel = _this.llmChannel) === null || _this$llmChannel === void 0 ? void 0 : _this$llmChannel.isConnected()) !== null && _this$llmChannel$isCo !== void 0 ? _this$llmChannel$isCo : false;
|
|
222
231
|
});
|
|
223
232
|
(0, _defineProperty2.default)(_this, "getKeepTranscriptionSubscribed", function () {
|
|
224
233
|
return _this.keepTranscriptionSubscribed;
|
|
@@ -228,9 +237,10 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
228
237
|
* @returns {void}
|
|
229
238
|
*/
|
|
230
239
|
(0, _defineProperty2.default)(_this, "sendAnnouncement", function () {
|
|
240
|
+
var llm = _this.requireLLMChannel();
|
|
231
241
|
_this.announceStatus = _constants.ANNOUNCE_STATUS.JOINING;
|
|
232
|
-
var socket =
|
|
233
|
-
var binding =
|
|
242
|
+
var socket = llm.getSocket();
|
|
243
|
+
var binding = llm.getBinding();
|
|
234
244
|
var payload = {
|
|
235
245
|
id: "".concat(_this.seqNum),
|
|
236
246
|
type: 'publishRequest',
|
|
@@ -262,7 +272,7 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
262
272
|
(0, _defineProperty2.default)(_this, "setSpokenLanguage", function (languageCode, languageAssignment) {
|
|
263
273
|
return _this.request({
|
|
264
274
|
method: 'PUT',
|
|
265
|
-
url: "".concat(_this.
|
|
275
|
+
url: "".concat(_this.requireLLMChannel().getLocusUrl(), "/controls/"),
|
|
266
276
|
body: {
|
|
267
277
|
transcribe: _objectSpread({
|
|
268
278
|
spokenLanguage: languageCode
|
|
@@ -285,8 +295,9 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
285
295
|
if (!_this.isLLMConnected()) {
|
|
286
296
|
return;
|
|
287
297
|
}
|
|
288
|
-
var
|
|
289
|
-
var
|
|
298
|
+
var llm = _this.requireLLMChannel();
|
|
299
|
+
var socket = llm.getSocket();
|
|
300
|
+
var binding = llm.getBinding();
|
|
290
301
|
socket.send({
|
|
291
302
|
id: "".concat(_this.seqNum),
|
|
292
303
|
type: 'publishRequest',
|
|
@@ -321,8 +332,9 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
321
332
|
if (!_this.isLLMConnected()) {
|
|
322
333
|
return;
|
|
323
334
|
}
|
|
324
|
-
var
|
|
325
|
-
var
|
|
335
|
+
var llm = _this.requireLLMChannel();
|
|
336
|
+
var socket = llm.getSocket();
|
|
337
|
+
var binding = llm.getBinding();
|
|
326
338
|
socket === null || socket === void 0 ? void 0 : socket.send({
|
|
327
339
|
id: "".concat(_this.seqNum),
|
|
328
340
|
type: 'publishRequest',
|
|
@@ -356,7 +368,7 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
356
368
|
*/
|
|
357
369
|
(0, _defineProperty2.default)(_this, "requestTurnOnCaptions", function (languageCode) {
|
|
358
370
|
_this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.SENDING;
|
|
359
|
-
var locusUrl = _this.
|
|
371
|
+
var locusUrl = _this.requireLLMChannel().getLocusUrl();
|
|
360
372
|
var body = {
|
|
361
373
|
transcribe: {
|
|
362
374
|
caption: true
|
|
@@ -377,7 +389,9 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
377
389
|
}, true);
|
|
378
390
|
}).catch(function (error) {
|
|
379
391
|
_this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.IDLE;
|
|
380
|
-
throw new Error('turn on captions fail'
|
|
392
|
+
throw new Error('turn on captions fail', {
|
|
393
|
+
cause: error
|
|
394
|
+
});
|
|
381
395
|
});
|
|
382
396
|
});
|
|
383
397
|
/**
|
|
@@ -424,7 +438,7 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
424
438
|
return _regenerator.default.wrap(function (_context) {
|
|
425
439
|
while (1) switch (_context.prev = _context.next) {
|
|
426
440
|
case 0:
|
|
427
|
-
if (!
|
|
441
|
+
if (!_this.isCaptionProcessing()) {
|
|
428
442
|
_context.next = 1;
|
|
429
443
|
break;
|
|
430
444
|
}
|
|
@@ -456,7 +470,7 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
456
470
|
(0, _defineProperty2.default)(_this, "toggleTranscribing", function (activate, spokenLanguage) {
|
|
457
471
|
return _this.request({
|
|
458
472
|
method: 'PUT',
|
|
459
|
-
url: "".concat(_this.
|
|
473
|
+
url: "".concat(_this.requireLLMChannel().getLocusUrl(), "/controls/"),
|
|
460
474
|
body: {
|
|
461
475
|
transcribe: {
|
|
462
476
|
transcribing: activate
|
|
@@ -480,7 +494,7 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
480
494
|
_this.toggleManualCaptionStatus = _constants.TOGGLE_MANUAL_CAPTION_STATUS.SENDING;
|
|
481
495
|
return _this.request({
|
|
482
496
|
method: 'PUT',
|
|
483
|
-
url: "".concat(_this.
|
|
497
|
+
url: "".concat(_this.requireLLMChannel().getLocusUrl(), "/controls/"),
|
|
484
498
|
body: {
|
|
485
499
|
manualCaption: {
|
|
486
500
|
enable: enable
|
|
@@ -550,6 +564,7 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
550
564
|
subscribe,
|
|
551
565
|
_ref3$unsubscribe,
|
|
552
566
|
unsubscribe,
|
|
567
|
+
llm,
|
|
553
568
|
isDataChannelTokenEnabled,
|
|
554
569
|
socket,
|
|
555
570
|
datachannelUrl,
|
|
@@ -564,8 +579,9 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
564
579
|
}
|
|
565
580
|
return _context2.abrupt("return");
|
|
566
581
|
case 1:
|
|
582
|
+
llm = _this.requireLLMChannel();
|
|
567
583
|
_context2.next = 2;
|
|
568
|
-
return
|
|
584
|
+
return llm.isDataChannelTokenEnabled();
|
|
569
585
|
case 2:
|
|
570
586
|
isDataChannelTokenEnabled = _context2.sent;
|
|
571
587
|
if (isDataChannelTokenEnabled) {
|
|
@@ -574,8 +590,8 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
574
590
|
}
|
|
575
591
|
return _context2.abrupt("return");
|
|
576
592
|
case 3:
|
|
577
|
-
socket =
|
|
578
|
-
datachannelUrl =
|
|
593
|
+
socket = llm.getSocket();
|
|
594
|
+
datachannelUrl = llm.getDatachannelUrl();
|
|
579
595
|
socket.send({
|
|
580
596
|
id: "".concat(_this.seqNum),
|
|
581
597
|
type: 'subchannelSubscriptionRequest',
|
|
@@ -623,13 +639,30 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
623
639
|
_this.currentCaptionLanguage = undefined;
|
|
624
640
|
_this.keepTranscriptionSubscribed = false;
|
|
625
641
|
|
|
626
|
-
// Subscribe to relay events from the LLM channel
|
|
627
|
-
_this.llmChannel
|
|
628
|
-
|
|
642
|
+
// Subscribe to relay events from the LLM channel if provided
|
|
643
|
+
if (_this.llmChannel) {
|
|
644
|
+
_this.llmChannel.on('event:relay.event', _this.eventProcessor);
|
|
645
|
+
_this.hasSubscribedToEvents = true;
|
|
646
|
+
}
|
|
629
647
|
return _this;
|
|
630
648
|
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Returns the LLM channel, throwing if not available.
|
|
652
|
+
* @private
|
|
653
|
+
* @returns {LLMChannel}
|
|
654
|
+
* @throws {Error} If LLM channel is not available
|
|
655
|
+
*/
|
|
631
656
|
(0, _inherits2.default)(VoiceaChannel, _EventEmitter);
|
|
632
657
|
return (0, _createClass2.default)(VoiceaChannel, [{
|
|
658
|
+
key: "requireLLMChannel",
|
|
659
|
+
value: function requireLLMChannel() {
|
|
660
|
+
if (!this.llmChannel) {
|
|
661
|
+
throw new Error('VoiceaChannel: LLM channel not available');
|
|
662
|
+
}
|
|
663
|
+
return this.llmChannel;
|
|
664
|
+
}
|
|
665
|
+
}, {
|
|
633
666
|
key: "deregisterEvents",
|
|
634
667
|
value:
|
|
635
668
|
/**
|
|
@@ -640,8 +673,14 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
640
673
|
this.areCaptionsEnabled = false;
|
|
641
674
|
this.keepTranscriptionSubscribed = false;
|
|
642
675
|
this.captionServiceId = undefined;
|
|
676
|
+
this.targetLLMChannel = undefined;
|
|
677
|
+
this._pendingCaptionRestore = false;
|
|
678
|
+
|
|
679
|
+
// Remove any pending online listener
|
|
680
|
+
this.detachPendingOnline();
|
|
643
681
|
if (this.hasSubscribedToEvents) {
|
|
644
|
-
|
|
682
|
+
var _this$llmChannel2;
|
|
683
|
+
(_this$llmChannel2 = this.llmChannel) === null || _this$llmChannel2 === void 0 ? void 0 : _this$llmChannel2.off('event:relay.event', this.eventProcessor);
|
|
645
684
|
this.hasSubscribedToEvents = false;
|
|
646
685
|
}
|
|
647
686
|
this.announceStatus = _constants.ANNOUNCE_STATUS.IDLE;
|
|
@@ -652,61 +691,109 @@ var VoiceaChannel = exports.VoiceaChannel = /*#__PURE__*/function (_EventEmitter
|
|
|
652
691
|
}
|
|
653
692
|
|
|
654
693
|
/**
|
|
655
|
-
*
|
|
656
|
-
*
|
|
657
|
-
* -
|
|
658
|
-
*
|
|
659
|
-
*
|
|
660
|
-
* @
|
|
661
|
-
* @returns {Promise<void>}
|
|
694
|
+
* Attach a pending 'online' listener to a channel for deferred reconciliation.
|
|
695
|
+
* Detaches any existing listener first.
|
|
696
|
+
* @param {LLMChannel} channel - The channel to attach to
|
|
697
|
+
* @param {Function} callback - The callback to run when 'online' fires
|
|
698
|
+
* @private
|
|
699
|
+
* @returns {void}
|
|
662
700
|
*/
|
|
663
701
|
}, {
|
|
664
|
-
key: "
|
|
665
|
-
value:
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
case 0:
|
|
671
|
-
// Save current state
|
|
672
|
-
captionsWereOn = this.keepTranscriptionSubscribed;
|
|
673
|
-
spokenLanguage = this.currentSpokenLanguage; // Unsubscribe from old channel
|
|
674
|
-
if (this.hasSubscribedToEvents && this.llmChannel) {
|
|
675
|
-
this.llmChannel.off('event:relay.event', this.eventProcessor);
|
|
676
|
-
this.hasSubscribedToEvents = false;
|
|
677
|
-
}
|
|
702
|
+
key: "attachPendingOnline",
|
|
703
|
+
value: function attachPendingOnline(channel, callback) {
|
|
704
|
+
this.detachPendingOnline();
|
|
705
|
+
this._pendingOnlineListener = callback;
|
|
706
|
+
channel.once('online', this._pendingOnlineListener);
|
|
707
|
+
}
|
|
678
708
|
|
|
679
|
-
|
|
680
|
-
|
|
709
|
+
/**
|
|
710
|
+
* Detach any pending 'online' listener.
|
|
711
|
+
* @private
|
|
712
|
+
* @returns {void}
|
|
713
|
+
*/
|
|
714
|
+
}, {
|
|
715
|
+
key: "detachPendingOnline",
|
|
716
|
+
value: function detachPendingOnline() {
|
|
717
|
+
if (this._pendingOnlineListener && this.llmChannel) {
|
|
718
|
+
this.llmChannel.off('online', this._pendingOnlineListener);
|
|
719
|
+
}
|
|
720
|
+
this._pendingOnlineListener = undefined;
|
|
721
|
+
}
|
|
681
722
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
723
|
+
/**
|
|
724
|
+
* Reset announcement state for a new connection.
|
|
725
|
+
* @private
|
|
726
|
+
* @returns {void}
|
|
727
|
+
*/
|
|
728
|
+
}, {
|
|
729
|
+
key: "resetAnnounceState",
|
|
730
|
+
value: function resetAnnounceState() {
|
|
731
|
+
this.announceStatus = _constants.ANNOUNCE_STATUS.IDLE;
|
|
732
|
+
this.captionStatus = _constants.TURN_ON_CAPTION_STATUS.IDLE;
|
|
733
|
+
this.captionServiceId = undefined;
|
|
734
|
+
this.areCaptionsEnabled = false;
|
|
735
|
+
}
|
|
685
736
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
737
|
+
/**
|
|
738
|
+
* Reconcile voicea binding and caption state to match the desired target.
|
|
739
|
+
* This is idempotent - always re-reads targetLLMChannel and current state.
|
|
740
|
+
* A deferred 'online' callback that fires late self-corrects automatically.
|
|
741
|
+
* @private
|
|
742
|
+
* @returns {Promise<void>}
|
|
743
|
+
*/
|
|
744
|
+
}, {
|
|
745
|
+
key: "reconcile",
|
|
746
|
+
value: function reconcile() {
|
|
747
|
+
var _this2 = this;
|
|
748
|
+
var target = this.targetLLMChannel;
|
|
749
|
+
if (!target) return _promise.default.resolve();
|
|
691
750
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
}));
|
|
705
|
-
function switchLLMChannel(_x2) {
|
|
706
|
-
return _switchLLMChannel.apply(this, arguments);
|
|
751
|
+
// 1. Rebind relay-event subscription if actual != desired
|
|
752
|
+
if (this.llmChannel !== target) {
|
|
753
|
+
if (this.hasSubscribedToEvents && this.llmChannel) {
|
|
754
|
+
this.llmChannel.off('event:relay.event', this.eventProcessor);
|
|
755
|
+
}
|
|
756
|
+
this.detachPendingOnline();
|
|
757
|
+
this.llmChannel = target;
|
|
758
|
+
this.llmChannel.on('event:relay.event', this.eventProcessor);
|
|
759
|
+
this.hasSubscribedToEvents = true;
|
|
760
|
+
this.resetAnnounceState();
|
|
761
|
+
// Mark caption restoration as pending if captions were subscribed
|
|
762
|
+
this._pendingCaptionRestore = this.keepTranscriptionSubscribed;
|
|
707
763
|
}
|
|
708
|
-
|
|
709
|
-
|
|
764
|
+
|
|
765
|
+
// 2. Restore captions if pending
|
|
766
|
+
if (!this._pendingCaptionRestore) return _promise.default.resolve();
|
|
767
|
+
if (this.isLLMConnected()) {
|
|
768
|
+
// Channel is connected, restore captions immediately
|
|
769
|
+
this._pendingCaptionRestore = false;
|
|
770
|
+
return this.turnOnCaptions(this.currentSpokenLanguage).then(function () {
|
|
771
|
+
return undefined;
|
|
772
|
+
}).catch(function () {
|
|
773
|
+
// Best-effort restoration
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
// Channel not yet connected - defer until 'online' then re-reconcile.
|
|
777
|
+
// If target changes meanwhile, reconcile() self-corrects.
|
|
778
|
+
this.attachPendingOnline(target, function () {
|
|
779
|
+
_this2.reconcile();
|
|
780
|
+
});
|
|
781
|
+
return _promise.default.resolve();
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
* Switch to a different LLM channel while preserving caption state.
|
|
786
|
+
* Used when transitioning between main meeting and practice session.
|
|
787
|
+
* This is a thin intent-setter - actual binding happens in reconcile().
|
|
788
|
+
* @param {LLMChannel} newLLMChannel - The new LLM channel to switch to
|
|
789
|
+
* @returns {Promise<void>}
|
|
790
|
+
*/
|
|
791
|
+
}, {
|
|
792
|
+
key: "switchLLMChannel",
|
|
793
|
+
value: function switchLLMChannel(newLLMChannel) {
|
|
794
|
+
this.targetLLMChannel = newLLMChannel;
|
|
795
|
+
return this.reconcile();
|
|
796
|
+
}
|
|
710
797
|
}]);
|
|
711
798
|
}(_events.default);
|
|
712
799
|
var _default = exports.default = VoiceaChannel;
|