@webex/internal-plugin-voicea 3.12.0-next.9 → 3.12.0-task-refactor.1
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 +1 -2
- package/dist/constants.js.map +1 -1
- package/dist/types/constants.d.ts +0 -1
- package/dist/types/voicea.d.ts +2 -56
- package/dist/voicea.js +24 -173
- package/dist/voicea.js.map +1 -1
- package/package.json +9 -9
- package/src/constants.ts +0 -1
- package/src/voicea.ts +24 -163
- package/test/unit/spec/voicea.js +20 -498
package/test/unit/spec/voicea.js
CHANGED
|
@@ -7,11 +7,7 @@ import Mercury from '@webex/internal-plugin-mercury';
|
|
|
7
7
|
import LLMChannel from '@webex/internal-plugin-llm';
|
|
8
8
|
|
|
9
9
|
import VoiceaService from '../../../src/index';
|
|
10
|
-
import {
|
|
11
|
-
EVENT_TRIGGERS,
|
|
12
|
-
LLM_PRACTICE_SESSION,
|
|
13
|
-
TOGGLE_MANUAL_CAPTION_STATUS,
|
|
14
|
-
} from '../../../src/constants';
|
|
10
|
+
import {EVENT_TRIGGERS, TOGGLE_MANUAL_CAPTION_STATUS} from '../../../src/constants';
|
|
15
11
|
|
|
16
12
|
describe('plugin-voicea', () => {
|
|
17
13
|
const locusUrl = 'locusUrl';
|
|
@@ -32,7 +28,6 @@ describe('plugin-voicea', () => {
|
|
|
32
28
|
voiceaService.connect = sinon.stub().resolves(true);
|
|
33
29
|
voiceaService.webex.internal.llm.isConnected = sinon.stub().returns(true);
|
|
34
30
|
voiceaService.webex.internal.llm.getBinding = sinon.stub().returns(undefined);
|
|
35
|
-
voiceaService.webex.internal.llm.getSocket = sinon.stub().returns(undefined);
|
|
36
31
|
voiceaService.webex.internal.llm.getLocusUrl = sinon.stub().returns(locusUrl);
|
|
37
32
|
|
|
38
33
|
voiceaService.request = sinon.stub().resolves({
|
|
@@ -92,34 +87,7 @@ describe('plugin-voicea', () => {
|
|
|
92
87
|
|
|
93
88
|
voiceaService.sendAnnouncement();
|
|
94
89
|
|
|
95
|
-
assert.
|
|
96
|
-
assert.calledWith(spy, 'event:relay.event', sinon.match.func);
|
|
97
|
-
assert.calledWith(spy, `event:relay.event:${LLM_PRACTICE_SESSION}`, sinon.match.func);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('includes captionServiceId in headers when set', () => {
|
|
101
|
-
const mockWebSocket = new MockWebSocket();
|
|
102
|
-
|
|
103
|
-
voiceaService.webex.internal.llm.socket = mockWebSocket;
|
|
104
|
-
voiceaService.announceStatus = 'idle';
|
|
105
|
-
voiceaService.captionServiceId = 'svc-123';
|
|
106
|
-
|
|
107
|
-
voiceaService.sendAnnouncement();
|
|
108
|
-
|
|
109
|
-
assert.calledOnceWithExactly(voiceaService.webex.internal.llm.socket.send, {
|
|
110
|
-
id: '1',
|
|
111
|
-
type: 'publishRequest',
|
|
112
|
-
recipients: {route: undefined},
|
|
113
|
-
headers: {to: 'svc-123'},
|
|
114
|
-
data: {
|
|
115
|
-
clientPayload: {
|
|
116
|
-
version: 'v2',
|
|
117
|
-
},
|
|
118
|
-
eventType: 'relay.event',
|
|
119
|
-
relayType: 'client.annc',
|
|
120
|
-
},
|
|
121
|
-
trackingId: sinon.match.string,
|
|
122
|
-
});
|
|
90
|
+
assert.calledOnceWithExactly(spy, 'event:relay.event', sinon.match.func);
|
|
123
91
|
});
|
|
124
92
|
});
|
|
125
93
|
|
|
@@ -221,32 +189,32 @@ describe('plugin-voicea', () => {
|
|
|
221
189
|
assert.notCalled(voiceaService.webex.internal.llm.socket.send);
|
|
222
190
|
});
|
|
223
191
|
});
|
|
192
|
+
|
|
224
193
|
describe('#deregisterEvents', () => {
|
|
225
194
|
beforeEach(async () => {
|
|
226
195
|
const mockWebSocket = new MockWebSocket();
|
|
196
|
+
|
|
227
197
|
voiceaService.webex.internal.llm.socket = mockWebSocket;
|
|
228
|
-
voiceaService.isCaptionBoxOn = true;
|
|
229
198
|
});
|
|
230
199
|
|
|
231
|
-
it('deregisters voicea service
|
|
200
|
+
it('deregisters voicea service', async () => {
|
|
232
201
|
voiceaService.listenToEvents();
|
|
233
202
|
await voiceaService.toggleTranscribing(true);
|
|
234
203
|
|
|
204
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
235
205
|
voiceaService.webex.internal.llm._emit('event:relay.event', {
|
|
236
206
|
headers: {from: 'ws'},
|
|
237
207
|
data: {relayType: 'voicea.annc', voiceaPayload: {}},
|
|
238
208
|
});
|
|
239
209
|
|
|
240
210
|
assert.equal(voiceaService.areCaptionsEnabled, true);
|
|
241
|
-
assert.equal(voiceaService.
|
|
242
|
-
assert.equal(voiceaService.isCaptionBoxOn, true);
|
|
211
|
+
assert.equal(voiceaService.vmcDeviceId, 'ws');
|
|
243
212
|
|
|
244
213
|
voiceaService.deregisterEvents();
|
|
245
214
|
assert.equal(voiceaService.areCaptionsEnabled, false);
|
|
246
|
-
assert.equal(voiceaService.
|
|
215
|
+
assert.equal(voiceaService.vmcDeviceId, undefined);
|
|
247
216
|
assert.equal(voiceaService.announceStatus, 'idle');
|
|
248
217
|
assert.equal(voiceaService.captionStatus, 'idle');
|
|
249
|
-
assert.equal(voiceaService.isCaptionBoxOn, false);
|
|
250
218
|
});
|
|
251
219
|
});
|
|
252
220
|
describe('#processAnnouncementMessage', () => {
|
|
@@ -276,7 +244,7 @@ describe('plugin-voicea', () => {
|
|
|
276
244
|
});
|
|
277
245
|
});
|
|
278
246
|
|
|
279
|
-
it('works on empty payload', async () => {
|
|
247
|
+
it('works on non-empty payload', async () => {
|
|
280
248
|
const spy = sinon.spy();
|
|
281
249
|
|
|
282
250
|
voiceaService.on(EVENT_TRIGGERS.VOICEA_ANNOUNCEMENT, spy);
|
|
@@ -318,28 +286,6 @@ describe('plugin-voicea', () => {
|
|
|
318
286
|
trackingId: sinon.match.string,
|
|
319
287
|
});
|
|
320
288
|
});
|
|
321
|
-
|
|
322
|
-
it('uses captionServiceId as "to" header when set', () => {
|
|
323
|
-
voiceaService.captionServiceId = 'svc-456';
|
|
324
|
-
|
|
325
|
-
voiceaService.requestLanguage('fr');
|
|
326
|
-
|
|
327
|
-
assert.calledOnceWithExactly(voiceaService.webex.internal.llm.socket.send, {
|
|
328
|
-
id: '1',
|
|
329
|
-
type: 'publishRequest',
|
|
330
|
-
recipients: {route: undefined},
|
|
331
|
-
headers: {to: 'svc-456'},
|
|
332
|
-
data: {
|
|
333
|
-
clientPayload: {
|
|
334
|
-
translationLanguage: 'fr',
|
|
335
|
-
id: sinon.match.string,
|
|
336
|
-
},
|
|
337
|
-
eventType: 'relay.event',
|
|
338
|
-
relayType: 'voicea.transl.req',
|
|
339
|
-
},
|
|
340
|
-
trackingId: sinon.match.string,
|
|
341
|
-
});
|
|
342
|
-
});
|
|
343
289
|
});
|
|
344
290
|
|
|
345
291
|
describe('#setSpokenLanguage', () => {
|
|
@@ -408,7 +354,6 @@ describe('plugin-voicea', () => {
|
|
|
408
354
|
|
|
409
355
|
it('turns on captions', async () => {
|
|
410
356
|
const announcementSpy = sinon.spy(voiceaService, 'announce');
|
|
411
|
-
const updateSubchannelSubscriptionsAndSyncCaptionStateSpy = sinon.spy(voiceaService, 'updateSubchannelSubscriptionsAndSyncCaptionState');
|
|
412
357
|
|
|
413
358
|
const triggerSpy = sinon.spy();
|
|
414
359
|
|
|
@@ -429,11 +374,6 @@ describe('plugin-voicea', () => {
|
|
|
429
374
|
assert.calledOnceWithExactly(triggerSpy);
|
|
430
375
|
|
|
431
376
|
assert.calledOnce(announcementSpy);
|
|
432
|
-
assert.calledOnceWithExactly(
|
|
433
|
-
updateSubchannelSubscriptionsAndSyncCaptionStateSpy,
|
|
434
|
-
{ subscribe: ['transcription'] },
|
|
435
|
-
true
|
|
436
|
-
);
|
|
437
377
|
});
|
|
438
378
|
|
|
439
379
|
it("should handle request fail", async () => {
|
|
@@ -468,61 +408,17 @@ describe('plugin-voicea', () => {
|
|
|
468
408
|
});
|
|
469
409
|
});
|
|
470
410
|
|
|
471
|
-
describe('#isLLMConnected', () => {
|
|
472
|
-
it('returns true when the default llm connection is connected', () => {
|
|
473
|
-
voiceaService.webex.internal.llm.isConnected.callsFake((channel) =>
|
|
474
|
-
channel === LLM_PRACTICE_SESSION ? false : true
|
|
475
|
-
);
|
|
476
|
-
|
|
477
|
-
assert.equal(voiceaService.isLLMConnected(), true);
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
it('returns true when only the practice session llm connection is connected', () => {
|
|
481
|
-
voiceaService.webex.internal.llm.isConnected.callsFake((channel) =>
|
|
482
|
-
channel === LLM_PRACTICE_SESSION
|
|
483
|
-
);
|
|
484
|
-
|
|
485
|
-
assert.equal(voiceaService.isLLMConnected(), true);
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
it('returns false when neither llm connection is connected', () => {
|
|
489
|
-
voiceaService.webex.internal.llm.isConnected.returns(false);
|
|
490
|
-
|
|
491
|
-
assert.equal(voiceaService.isLLMConnected(), false);
|
|
492
|
-
});
|
|
493
|
-
});
|
|
494
|
-
|
|
495
|
-
describe('#getIsCaptionBoxOn', () => {
|
|
496
|
-
beforeEach(() => {
|
|
497
|
-
voiceaService.isCaptionBoxOn = false;
|
|
498
|
-
});
|
|
499
|
-
|
|
500
|
-
it('returns false when captions are disabled', () => {
|
|
501
|
-
voiceaService.isCaptionBoxOn = false;
|
|
502
|
-
|
|
503
|
-
const result = voiceaService.getIsCaptionBoxOn();
|
|
504
|
-
|
|
505
|
-
assert.equal(result, false);
|
|
506
|
-
});
|
|
507
|
-
|
|
508
|
-
it('returns true when captions are enabled', () => {
|
|
509
|
-
voiceaService.isCaptionBoxOn = true;
|
|
510
|
-
|
|
511
|
-
const result = voiceaService.getIsCaptionBoxOn();
|
|
512
|
-
|
|
513
|
-
assert.equal(result, true);
|
|
514
|
-
});
|
|
515
|
-
});
|
|
516
|
-
|
|
517
411
|
describe("#announce", () => {
|
|
518
|
-
let
|
|
412
|
+
let isAnnounceProcessing, sendAnnouncement;
|
|
519
413
|
beforeEach(() => {
|
|
414
|
+
voiceaService.webex.internal.llm.isConnected.returns(true);
|
|
520
415
|
sendAnnouncement = sinon.stub(voiceaService, 'sendAnnouncement');
|
|
521
|
-
|
|
416
|
+
isAnnounceProcessing = sinon.stub(voiceaService, 'isAnnounceProcessing').returns(false)
|
|
522
417
|
});
|
|
523
418
|
|
|
524
419
|
afterEach(() => {
|
|
525
|
-
|
|
420
|
+
voiceaService.webex.internal.llm.isConnected.returns(true);
|
|
421
|
+
isAnnounceProcessing.restore();
|
|
526
422
|
sendAnnouncement.restore();
|
|
527
423
|
});
|
|
528
424
|
|
|
@@ -537,18 +433,8 @@ describe('plugin-voicea', () => {
|
|
|
537
433
|
assert.notCalled(sendAnnouncement);
|
|
538
434
|
});
|
|
539
435
|
|
|
540
|
-
it('announce to llm data channel when only practice session is connected', ()=> {
|
|
541
|
-
voiceaService.webex.internal.llm.isConnected.callsFake((channel) =>
|
|
542
|
-
channel === LLM_PRACTICE_SESSION
|
|
543
|
-
);
|
|
544
|
-
|
|
545
|
-
voiceaService.announce();
|
|
546
|
-
|
|
547
|
-
assert.calledOnce(sendAnnouncement);
|
|
548
|
-
});
|
|
549
|
-
|
|
550
436
|
it('should not announce duplicate', () => {
|
|
551
|
-
|
|
437
|
+
isAnnounceProcessing.returns(true);
|
|
552
438
|
voiceaService.announce();
|
|
553
439
|
assert.notCalled(sendAnnouncement);
|
|
554
440
|
})
|
|
@@ -577,11 +463,13 @@ describe('plugin-voicea', () => {
|
|
|
577
463
|
beforeEach(() => {
|
|
578
464
|
requestTurnOnCaptions = sinon.stub(voiceaService, 'requestTurnOnCaptions');
|
|
579
465
|
voiceaService.captionStatus = 'idle';
|
|
466
|
+
voiceaService.webex.internal.llm.isConnected.returns(true);
|
|
580
467
|
});
|
|
581
468
|
|
|
582
469
|
afterEach(() => {
|
|
583
470
|
requestTurnOnCaptions.restore();
|
|
584
471
|
voiceaService.captionStatus = 'idle';
|
|
472
|
+
voiceaService.webex.internal.llm.isConnected.returns(true);
|
|
585
473
|
});
|
|
586
474
|
|
|
587
475
|
it('call request turn on captions', () => {
|
|
@@ -590,27 +478,13 @@ describe('plugin-voicea', () => {
|
|
|
590
478
|
assert.calledOnce(requestTurnOnCaptions);
|
|
591
479
|
});
|
|
592
480
|
|
|
593
|
-
it(
|
|
481
|
+
it("turns on captions before llm connected", () => {
|
|
594
482
|
voiceaService.captionStatus = 'idle';
|
|
595
|
-
voiceaService.webex.internal.llm.isConnected.returns(
|
|
596
|
-
|
|
597
|
-
await assert.isRejected(
|
|
598
|
-
voiceaService.turnOnCaptions(),
|
|
599
|
-
'can not turn on captions before llm connected'
|
|
600
|
-
);
|
|
483
|
+
voiceaService.webex.internal.llm.isConnected.returns(true);
|
|
484
|
+
// assert.throws(() => voiceaService.turnOnCaptions(), "can not turn on captions before llm connected");
|
|
601
485
|
assert.notCalled(requestTurnOnCaptions);
|
|
602
486
|
});
|
|
603
487
|
|
|
604
|
-
it('turns on captions when only the practice session llm connection is connected', () => {
|
|
605
|
-
voiceaService.webex.internal.llm.isConnected.callsFake((channel) =>
|
|
606
|
-
channel === LLM_PRACTICE_SESSION
|
|
607
|
-
);
|
|
608
|
-
|
|
609
|
-
voiceaService.turnOnCaptions();
|
|
610
|
-
|
|
611
|
-
assert.calledOnce(requestTurnOnCaptions);
|
|
612
|
-
});
|
|
613
|
-
|
|
614
488
|
it('should not turn on duplicate when processing', () => {
|
|
615
489
|
voiceaService.captionStatus = 'sending';
|
|
616
490
|
voiceaService.turnOnCaptions();
|
|
@@ -1227,357 +1101,5 @@ describe('plugin-voicea', () => {
|
|
|
1227
1101
|
assert.calledOnceWithExactly(triggerSpy, {languageCode, meetingId: '123'});
|
|
1228
1102
|
});
|
|
1229
1103
|
});
|
|
1230
|
-
|
|
1231
|
-
describe('#onCaptionServiceIdUpdate', () => {
|
|
1232
|
-
let mockWebSocket;
|
|
1233
|
-
|
|
1234
|
-
beforeEach(() => {
|
|
1235
|
-
mockWebSocket = new MockWebSocket();
|
|
1236
|
-
voiceaService.webex.internal.llm.socket = mockWebSocket;
|
|
1237
|
-
voiceaService.webex.internal.llm.isConnected.returns(true);
|
|
1238
|
-
voiceaService.seqNum = 1;
|
|
1239
|
-
});
|
|
1240
|
-
|
|
1241
|
-
it('does nothing when serviceId is falsy', () => {
|
|
1242
|
-
voiceaService.captionServiceId = 'existing-id';
|
|
1243
|
-
voiceaService.currentCaptionLanguage = 'en';
|
|
1244
|
-
|
|
1245
|
-
voiceaService.onCaptionServiceIdUpdate(undefined);
|
|
1246
|
-
voiceaService.onCaptionServiceIdUpdate('');
|
|
1247
|
-
|
|
1248
|
-
assert.equal(voiceaService.captionServiceId, 'existing-id');
|
|
1249
|
-
assert.notCalled(voiceaService.webex.internal.llm.socket.send);
|
|
1250
|
-
});
|
|
1251
|
-
|
|
1252
|
-
it('sets captionServiceId when no currentCaptionLanguage', () => {
|
|
1253
|
-
voiceaService.captionServiceId = undefined;
|
|
1254
|
-
voiceaService.currentCaptionLanguage = undefined;
|
|
1255
|
-
|
|
1256
|
-
voiceaService.onCaptionServiceIdUpdate('svc-new');
|
|
1257
|
-
|
|
1258
|
-
assert.equal(voiceaService.captionServiceId, 'svc-new');
|
|
1259
|
-
assert.notCalled(voiceaService.webex.internal.llm.socket.send);
|
|
1260
|
-
});
|
|
1261
|
-
|
|
1262
|
-
it('re-sends language when serviceId changes and currentCaptionLanguage is set', () => {
|
|
1263
|
-
voiceaService.captionServiceId = 'old-svc';
|
|
1264
|
-
voiceaService.currentCaptionLanguage = 'es';
|
|
1265
|
-
|
|
1266
|
-
voiceaService.onCaptionServiceIdUpdate('new-svc');
|
|
1267
|
-
|
|
1268
|
-
assert.equal(voiceaService.captionServiceId, 'new-svc');
|
|
1269
|
-
assert.calledOnce(voiceaService.webex.internal.llm.socket.send);
|
|
1270
|
-
|
|
1271
|
-
const callArgs = voiceaService.webex.internal.llm.socket.send.getCall(0).args[0];
|
|
1272
|
-
expect(callArgs).to.have.nested.property('headers.to', 'new-svc');
|
|
1273
|
-
expect(callArgs).to.have.nested.property('data.clientPayload.translationLanguage', 'es');
|
|
1274
|
-
});
|
|
1275
|
-
|
|
1276
|
-
it('does not re-send language when serviceId is unchanged', () => {
|
|
1277
|
-
voiceaService.captionServiceId = 'same-svc';
|
|
1278
|
-
voiceaService.currentCaptionLanguage = 'de';
|
|
1279
|
-
|
|
1280
|
-
voiceaService.onCaptionServiceIdUpdate('same-svc');
|
|
1281
|
-
|
|
1282
|
-
assert.equal(voiceaService.captionServiceId, 'same-svc');
|
|
1283
|
-
assert.notCalled(voiceaService.webex.internal.llm.socket.send);
|
|
1284
|
-
});
|
|
1285
|
-
});
|
|
1286
|
-
|
|
1287
|
-
describe('#updateSubchannelSubscriptions', () => {
|
|
1288
|
-
beforeEach(() => {
|
|
1289
|
-
const mockWebSocket = new MockWebSocket();
|
|
1290
|
-
|
|
1291
|
-
sinon.stub(voiceaService, 'getPublishTransport').returns({
|
|
1292
|
-
socket: mockWebSocket,
|
|
1293
|
-
datachannelUrl: 'mock-datachannel-uri',
|
|
1294
|
-
});
|
|
1295
|
-
|
|
1296
|
-
voiceaService.seqNum = 1;
|
|
1297
|
-
|
|
1298
|
-
voiceaService.isLLMConnected = sinon.stub().returns(true);
|
|
1299
|
-
voiceaService.webex.internal.llm.isDataChannelTokenEnabled = sinon.stub().resolves(true);
|
|
1300
|
-
});
|
|
1301
|
-
|
|
1302
|
-
it('sends subchannelSubscriptionRequest with subscribe and unsubscribe lists', async () => {
|
|
1303
|
-
await voiceaService.updateSubchannelSubscriptions({
|
|
1304
|
-
subscribe: ['transcription'],
|
|
1305
|
-
unsubscribe: ['polls'],
|
|
1306
|
-
});
|
|
1307
|
-
|
|
1308
|
-
const socket = voiceaService.getPublishTransport().socket;
|
|
1309
|
-
|
|
1310
|
-
sinon.assert.calledOnceWithExactly(
|
|
1311
|
-
socket.send,
|
|
1312
|
-
{
|
|
1313
|
-
id: '1',
|
|
1314
|
-
type: 'subchannelSubscriptionRequest',
|
|
1315
|
-
data: {
|
|
1316
|
-
datachannelUri: 'mock-datachannel-uri',
|
|
1317
|
-
subscribe: ['transcription'],
|
|
1318
|
-
unsubscribe: ['polls'],
|
|
1319
|
-
},
|
|
1320
|
-
trackingId: sinon.match.string,
|
|
1321
|
-
}
|
|
1322
|
-
);
|
|
1323
|
-
|
|
1324
|
-
sinon.assert.match(voiceaService.seqNum, 2);
|
|
1325
|
-
});
|
|
1326
|
-
|
|
1327
|
-
it('sends empty arrays when no subscribe/unsubscribe provided', async () => {
|
|
1328
|
-
await voiceaService.updateSubchannelSubscriptions({});
|
|
1329
|
-
|
|
1330
|
-
const socket = voiceaService.getPublishTransport().socket;
|
|
1331
|
-
|
|
1332
|
-
sinon.assert.calledOnceWithExactly(
|
|
1333
|
-
socket.send,
|
|
1334
|
-
{
|
|
1335
|
-
id: '1',
|
|
1336
|
-
type: 'subchannelSubscriptionRequest',
|
|
1337
|
-
data: {
|
|
1338
|
-
datachannelUri: 'mock-datachannel-uri',
|
|
1339
|
-
subscribe: [],
|
|
1340
|
-
unsubscribe: [],
|
|
1341
|
-
},
|
|
1342
|
-
trackingId: sinon.match.string,
|
|
1343
|
-
}
|
|
1344
|
-
);
|
|
1345
|
-
|
|
1346
|
-
sinon.assert.match(voiceaService.seqNum, 2);
|
|
1347
|
-
});
|
|
1348
|
-
|
|
1349
|
-
it('does nothing when LLM is not connected', async () => {
|
|
1350
|
-
voiceaService.isLLMConnected = sinon.stub().returns(false);
|
|
1351
|
-
|
|
1352
|
-
await voiceaService.updateSubchannelSubscriptions({
|
|
1353
|
-
subscribe: ['transcription'],
|
|
1354
|
-
});
|
|
1355
|
-
|
|
1356
|
-
const socket = voiceaService.getPublishTransport().socket;
|
|
1357
|
-
|
|
1358
|
-
sinon.assert.notCalled(socket.send);
|
|
1359
|
-
sinon.assert.match(voiceaService.seqNum, 1);
|
|
1360
|
-
});
|
|
1361
|
-
|
|
1362
|
-
it('does nothing when dataChannelToken is not enabled', async () => {
|
|
1363
|
-
voiceaService.webex.internal.llm.isDataChannelTokenEnabled = sinon.stub().resolves(false);
|
|
1364
|
-
|
|
1365
|
-
await voiceaService.updateSubchannelSubscriptions({
|
|
1366
|
-
subscribe: ['transcription'],
|
|
1367
|
-
});
|
|
1368
|
-
|
|
1369
|
-
const socket = voiceaService.getPublishTransport().socket;
|
|
1370
|
-
|
|
1371
|
-
sinon.assert.notCalled(socket.send);
|
|
1372
|
-
sinon.assert.match(voiceaService.seqNum, 1);
|
|
1373
|
-
});
|
|
1374
|
-
});
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
describe('#updateSubchannelSubscriptionsAndSyncCaptionState', () => {
|
|
1378
|
-
beforeEach(() => {
|
|
1379
|
-
const mockWebSocket = new MockWebSocket();
|
|
1380
|
-
voiceaService.webex.internal.llm.socket = mockWebSocket;
|
|
1381
|
-
|
|
1382
|
-
voiceaService.webex.internal.llm.getDatachannelUrl = sinon.stub().returns('mock-datachannel-uri');
|
|
1383
|
-
|
|
1384
|
-
voiceaService.seqNum = 1;
|
|
1385
|
-
|
|
1386
|
-
voiceaService.isLLMConnected = sinon.stub().returns(true);
|
|
1387
|
-
voiceaService.webex.internal.llm.isDataChannelTokenEnabled = sinon.stub().resolves(true);
|
|
1388
|
-
|
|
1389
|
-
sinon.spy(voiceaService, 'updateSubchannelSubscriptions');
|
|
1390
|
-
});
|
|
1391
|
-
|
|
1392
|
-
afterEach(() => {
|
|
1393
|
-
sinon.restore();
|
|
1394
|
-
});
|
|
1395
|
-
|
|
1396
|
-
it('updates caption intent and forwards subscribe/unsubscribe to updateSubchannelSubscriptions', async () => {
|
|
1397
|
-
await voiceaService.updateSubchannelSubscriptionsAndSyncCaptionState(
|
|
1398
|
-
{
|
|
1399
|
-
subscribe: ['transcription'],
|
|
1400
|
-
unsubscribe: ['polls'],
|
|
1401
|
-
},
|
|
1402
|
-
true
|
|
1403
|
-
);
|
|
1404
|
-
|
|
1405
|
-
assert.equal(voiceaService.isCaptionBoxOn, true);
|
|
1406
|
-
|
|
1407
|
-
assert.calledOnceWithExactly(
|
|
1408
|
-
voiceaService.updateSubchannelSubscriptions,
|
|
1409
|
-
{
|
|
1410
|
-
subscribe: ['transcription'],
|
|
1411
|
-
unsubscribe: ['polls'],
|
|
1412
|
-
}
|
|
1413
|
-
);
|
|
1414
|
-
});
|
|
1415
|
-
|
|
1416
|
-
it('sets caption intent to false when isCCBoxOpen is false', async () => {
|
|
1417
|
-
await voiceaService.updateSubchannelSubscriptionsAndSyncCaptionState(
|
|
1418
|
-
{ subscribe: ['transcription'] },
|
|
1419
|
-
false
|
|
1420
|
-
);
|
|
1421
|
-
|
|
1422
|
-
assert.equal(voiceaService.isCaptionBoxOn, false);
|
|
1423
|
-
|
|
1424
|
-
assert.calledOnceWithExactly(
|
|
1425
|
-
voiceaService.updateSubchannelSubscriptions,
|
|
1426
|
-
{ subscribe: ['transcription'] }
|
|
1427
|
-
);
|
|
1428
|
-
});
|
|
1429
|
-
|
|
1430
|
-
it('defaults subscribe/unsubscribe to empty arrays when options is empty', async () => {
|
|
1431
|
-
await voiceaService.updateSubchannelSubscriptionsAndSyncCaptionState({}, true);
|
|
1432
|
-
|
|
1433
|
-
assert.equal(voiceaService.isCaptionBoxOn, true);
|
|
1434
|
-
|
|
1435
|
-
assert.calledOnceWithExactly(
|
|
1436
|
-
voiceaService.updateSubchannelSubscriptions,
|
|
1437
|
-
{}
|
|
1438
|
-
);
|
|
1439
|
-
});
|
|
1440
|
-
|
|
1441
|
-
it('still updates caption intent even if updateSubchannelSubscriptions does nothing (e.g., LLM not connected)', async () => {
|
|
1442
|
-
voiceaService.isLLMConnected = sinon.stub().returns(false);
|
|
1443
|
-
|
|
1444
|
-
await voiceaService.updateSubchannelSubscriptionsAndSyncCaptionState(
|
|
1445
|
-
{ subscribe: ['transcription'] },
|
|
1446
|
-
true
|
|
1447
|
-
);
|
|
1448
|
-
|
|
1449
|
-
assert.equal(voiceaService.isCaptionBoxOn, true);
|
|
1450
|
-
|
|
1451
|
-
assert.calledOnceWithExactly(
|
|
1452
|
-
voiceaService.updateSubchannelSubscriptions,
|
|
1453
|
-
{ subscribe: ['transcription'] }
|
|
1454
|
-
);
|
|
1455
|
-
});
|
|
1456
|
-
});
|
|
1457
|
-
|
|
1458
|
-
describe('#multiple llm connections', () => {
|
|
1459
|
-
let defaultSocket;
|
|
1460
|
-
let practiceSocket;
|
|
1461
|
-
let isPracticeSessionConnected;
|
|
1462
|
-
|
|
1463
|
-
beforeEach(() => {
|
|
1464
|
-
defaultSocket = new MockWebSocket();
|
|
1465
|
-
practiceSocket = new MockWebSocket();
|
|
1466
|
-
isPracticeSessionConnected = true;
|
|
1467
|
-
|
|
1468
|
-
voiceaService.webex.internal.llm.socket = defaultSocket;
|
|
1469
|
-
voiceaService.webex.internal.llm.isConnected.callsFake((channel) =>
|
|
1470
|
-
channel === LLM_PRACTICE_SESSION ? isPracticeSessionConnected : true
|
|
1471
|
-
);
|
|
1472
|
-
voiceaService.webex.internal.llm.getSocket.callsFake((channel) =>
|
|
1473
|
-
channel === LLM_PRACTICE_SESSION ? practiceSocket : undefined
|
|
1474
|
-
);
|
|
1475
|
-
voiceaService.webex.internal.llm.getBinding.callsFake((channel) =>
|
|
1476
|
-
channel === LLM_PRACTICE_SESSION ? 'practice-binding' : 'default-binding'
|
|
1477
|
-
);
|
|
1478
|
-
voiceaService.seqNum = 1;
|
|
1479
|
-
});
|
|
1480
|
-
|
|
1481
|
-
it('sendAnnouncement uses the practice session socket and binding when available', () => {
|
|
1482
|
-
voiceaService.announceStatus = 'idle';
|
|
1483
|
-
|
|
1484
|
-
voiceaService.sendAnnouncement();
|
|
1485
|
-
|
|
1486
|
-
assert.calledOnce(practiceSocket.send);
|
|
1487
|
-
assert.notCalled(defaultSocket.send);
|
|
1488
|
-
|
|
1489
|
-
const sent = practiceSocket.send.getCall(0).args[0];
|
|
1490
|
-
expect(sent).to.have.nested.property('recipients.route', 'practice-binding');
|
|
1491
|
-
});
|
|
1492
|
-
|
|
1493
|
-
it('sendAnnouncement falls back to the default socket and binding when the practice session is not connected', () => {
|
|
1494
|
-
voiceaService.announceStatus = 'idle';
|
|
1495
|
-
isPracticeSessionConnected = false;
|
|
1496
|
-
|
|
1497
|
-
voiceaService.sendAnnouncement();
|
|
1498
|
-
|
|
1499
|
-
assert.calledOnce(defaultSocket.send);
|
|
1500
|
-
assert.notCalled(practiceSocket.send);
|
|
1501
|
-
|
|
1502
|
-
const sent = defaultSocket.send.getCall(0).args[0];
|
|
1503
|
-
expect(sent).to.have.nested.property('recipients.route', 'default-binding');
|
|
1504
|
-
});
|
|
1505
|
-
|
|
1506
|
-
it('requestLanguage uses the practice session socket and binding when available', () => {
|
|
1507
|
-
voiceaService.requestLanguage('fr');
|
|
1508
|
-
|
|
1509
|
-
assert.calledOnce(practiceSocket.send);
|
|
1510
|
-
assert.notCalled(defaultSocket.send);
|
|
1511
|
-
|
|
1512
|
-
const sent = practiceSocket.send.getCall(0).args[0];
|
|
1513
|
-
expect(sent).to.have.nested.property('recipients.route', 'practice-binding');
|
|
1514
|
-
expect(sent).to.have.nested.property('data.clientPayload.translationLanguage', 'fr');
|
|
1515
|
-
});
|
|
1516
|
-
|
|
1517
|
-
it('requestLanguage falls back to the default socket and binding when the practice session is not connected', () => {
|
|
1518
|
-
isPracticeSessionConnected = false;
|
|
1519
|
-
|
|
1520
|
-
voiceaService.requestLanguage('fr');
|
|
1521
|
-
|
|
1522
|
-
assert.calledOnce(defaultSocket.send);
|
|
1523
|
-
assert.notCalled(practiceSocket.send);
|
|
1524
|
-
|
|
1525
|
-
const sent = defaultSocket.send.getCall(0).args[0];
|
|
1526
|
-
expect(sent).to.have.nested.property('recipients.route', 'default-binding');
|
|
1527
|
-
expect(sent).to.have.nested.property('data.clientPayload.translationLanguage', 'fr');
|
|
1528
|
-
});
|
|
1529
|
-
|
|
1530
|
-
it('sendManualClosedCaption uses the practice session socket and binding when available', () => {
|
|
1531
|
-
voiceaService.sendManualClosedCaption('caption', 123, [456], true);
|
|
1532
|
-
|
|
1533
|
-
assert.calledOnce(practiceSocket.send);
|
|
1534
|
-
assert.notCalled(defaultSocket.send);
|
|
1535
|
-
|
|
1536
|
-
const sent = practiceSocket.send.getCall(0).args[0];
|
|
1537
|
-
expect(sent).to.have.nested.property('recipients.route', 'practice-binding');
|
|
1538
|
-
expect(sent).to.have.nested.property(
|
|
1539
|
-
'data.transcriptPayload.type',
|
|
1540
|
-
'manual_caption_final_result'
|
|
1541
|
-
);
|
|
1542
|
-
});
|
|
1543
|
-
|
|
1544
|
-
it('sendManualClosedCaption falls back to the default socket and binding when the practice session is not connected', () => {
|
|
1545
|
-
isPracticeSessionConnected = false;
|
|
1546
|
-
|
|
1547
|
-
voiceaService.sendManualClosedCaption('caption', 123, [456], false);
|
|
1548
|
-
|
|
1549
|
-
assert.calledOnce(defaultSocket.send);
|
|
1550
|
-
assert.notCalled(practiceSocket.send);
|
|
1551
|
-
|
|
1552
|
-
const sent = defaultSocket.send.getCall(0).args[0];
|
|
1553
|
-
expect(sent).to.have.nested.property('recipients.route', 'default-binding');
|
|
1554
|
-
expect(sent).to.have.nested.property(
|
|
1555
|
-
'data.transcriptPayload.type',
|
|
1556
|
-
'manual_caption_interim_result'
|
|
1557
|
-
);
|
|
1558
|
-
});
|
|
1559
|
-
|
|
1560
|
-
it('processes relay events from the practice session channel', async () => {
|
|
1561
|
-
const announcementSpy = sinon.spy(voiceaService, 'processAnnouncementMessage');
|
|
1562
|
-
|
|
1563
|
-
voiceaService.listenToEvents();
|
|
1564
|
-
|
|
1565
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
1566
|
-
await voiceaService.webex.internal.llm._emit(`event:relay.event:${LLM_PRACTICE_SESSION}`, {
|
|
1567
|
-
headers: {from: 'svc-practice'},
|
|
1568
|
-
data: {
|
|
1569
|
-
relayType: 'voicea.annc',
|
|
1570
|
-
voiceaPayload: {
|
|
1571
|
-
translation: {allowed_languages: ['en'], max_languages: 1},
|
|
1572
|
-
ASR: {spoken_languages: ['en']},
|
|
1573
|
-
},
|
|
1574
|
-
},
|
|
1575
|
-
sequenceNumber: 10,
|
|
1576
|
-
});
|
|
1577
|
-
|
|
1578
|
-
assert.calledOnce(announcementSpy);
|
|
1579
|
-
assert.equal(voiceaService.captionServiceId, 'svc-practice');
|
|
1580
|
-
});
|
|
1581
|
-
});
|
|
1582
1104
|
});
|
|
1583
1105
|
});
|