@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.
@@ -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.calledTwice(spy);
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 and resets caption state', async () => {
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.captionServiceId, 'ws');
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.captionServiceId, undefined);
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 isAnnounceProcessed, sendAnnouncement;
412
+ let isAnnounceProcessing, sendAnnouncement;
519
413
  beforeEach(() => {
414
+ voiceaService.webex.internal.llm.isConnected.returns(true);
520
415
  sendAnnouncement = sinon.stub(voiceaService, 'sendAnnouncement');
521
- isAnnounceProcessed = sinon.stub(voiceaService, 'isAnnounceProcessed').returns(false)
416
+ isAnnounceProcessing = sinon.stub(voiceaService, 'isAnnounceProcessing').returns(false)
522
417
  });
523
418
 
524
419
  afterEach(() => {
525
- isAnnounceProcessed.restore();
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
- isAnnounceProcessed.returns(true);
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('throws before turning on captions when llm is not connected', async () => {
481
+ it("turns on captions before llm connected", () => {
594
482
  voiceaService.captionStatus = 'idle';
595
- voiceaService.webex.internal.llm.isConnected.returns(false);
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
  });