@webex/plugin-meetings 3.12.0-next.1 → 3.12.0-next.10
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/aiEnableRequest/index.js +1 -1
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/hashTree/constants.js +10 -1
- package/dist/hashTree/constants.js.map +1 -1
- package/dist/hashTree/hashTreeParser.js +20 -11
- package/dist/hashTree/hashTreeParser.js.map +1 -1
- package/dist/hashTree/utils.js +22 -0
- package/dist/hashTree/utils.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/meeting/index.js +427 -323
- package/dist/meeting/index.js.map +1 -1
- package/dist/metrics/constants.js +5 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +116 -2
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/types/hashTree/constants.d.ts +1 -0
- package/dist/types/hashTree/utils.d.ts +11 -0
- package/dist/types/meeting/index.d.ts +24 -1
- package/dist/types/metrics/constants.d.ts +4 -0
- package/dist/types/multistream/sendSlotManager.d.ts +23 -1
- package/dist/webinar/index.js +325 -220
- package/dist/webinar/index.js.map +1 -1
- package/package.json +15 -15
- package/src/hashTree/constants.ts +9 -0
- package/src/hashTree/hashTreeParser.ts +21 -14
- package/src/hashTree/utils.ts +17 -0
- package/src/meeting/index.ts +165 -57
- package/src/metrics/constants.ts +5 -0
- package/src/multistream/sendSlotManager.ts +97 -3
- package/src/webinar/index.ts +120 -18
- package/test/unit/spec/hashTree/hashTreeParser.ts +238 -0
- package/test/unit/spec/hashTree/utils.ts +88 -1
- package/test/unit/spec/meeting/index.js +179 -48
- package/test/unit/spec/meetings/index.js +3 -3
- package/test/unit/spec/multistream/sendSlotManager.ts +135 -36
- package/test/unit/spec/webinar/index.ts +193 -8
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
import {
|
|
39
39
|
ConnectionState,
|
|
40
40
|
MediaConnectionEventNames,
|
|
41
|
+
MediaCodecMimeType,
|
|
41
42
|
StatsAnalyzerEventNames,
|
|
42
43
|
StatsMonitorEventNames,
|
|
43
44
|
Errors,
|
|
@@ -1552,6 +1553,22 @@ describe('plugin-meetings', () => {
|
|
|
1552
1553
|
EVENT_TRIGGERS.MEETING_STOPPED_RECEIVING_TRANSCRIPTION
|
|
1553
1554
|
);
|
|
1554
1555
|
});
|
|
1556
|
+
|
|
1557
|
+
it('should stop listening to voicea events even when transcription is undefined', () => {
|
|
1558
|
+
meeting.transcription = undefined;
|
|
1559
|
+
meeting.stopTranscription();
|
|
1560
|
+
assert.equal(webex.internal.voicea.off.callCount, 4);
|
|
1561
|
+
assert.equal(meeting.areVoiceaEventsSetup, false);
|
|
1562
|
+
assert.calledWith(
|
|
1563
|
+
TriggerProxy.trigger,
|
|
1564
|
+
sinon.match.instanceOf(Meeting),
|
|
1565
|
+
{
|
|
1566
|
+
file: 'meeting/index',
|
|
1567
|
+
function: 'triggerStopReceivingTranscriptionEvent',
|
|
1568
|
+
},
|
|
1569
|
+
EVENT_TRIGGERS.MEETING_STOPPED_RECEIVING_TRANSCRIPTION
|
|
1570
|
+
);
|
|
1571
|
+
});
|
|
1555
1572
|
});
|
|
1556
1573
|
|
|
1557
1574
|
describe('#setCaptionLanguage', () => {
|
|
@@ -1965,11 +1982,12 @@ describe('plugin-meetings', () => {
|
|
|
1965
1982
|
describe('#handleLLMOnline', () => {
|
|
1966
1983
|
beforeEach(() => {
|
|
1967
1984
|
webex.internal.llm.off = sinon.stub();
|
|
1985
|
+
webex.internal.voicea.getIsCaptionBoxOn = sinon.stub().returns(false);
|
|
1986
|
+
webex.internal.voicea.updateSubchannelSubscriptions = sinon.stub();
|
|
1968
1987
|
});
|
|
1969
1988
|
|
|
1970
|
-
it('
|
|
1989
|
+
it('emits transcription connected events', () => {
|
|
1971
1990
|
meeting.handleLLMOnline();
|
|
1972
|
-
assert.calledOnceWithExactly(webex.internal.llm.off, 'online', meeting.handleLLMOnline);
|
|
1973
1991
|
assert.calledWith(
|
|
1974
1992
|
TriggerProxy.trigger,
|
|
1975
1993
|
sinon.match.instanceOf(Meeting),
|
|
@@ -1980,6 +1998,24 @@ describe('plugin-meetings', () => {
|
|
|
1980
1998
|
EVENT_TRIGGERS.MEETING_TRANSCRIPTION_CONNECTED
|
|
1981
1999
|
);
|
|
1982
2000
|
});
|
|
2001
|
+
|
|
2002
|
+
it('restores transcription subscription when caption intent is enabled', () => {
|
|
2003
|
+
webex.internal.voicea.getIsCaptionBoxOn.returns(true);
|
|
2004
|
+
|
|
2005
|
+
meeting.handleLLMOnline();
|
|
2006
|
+
|
|
2007
|
+
assert.calledOnceWithExactly(webex.internal.voicea.updateSubchannelSubscriptions, {
|
|
2008
|
+
subscribe: ['transcription'],
|
|
2009
|
+
});
|
|
2010
|
+
});
|
|
2011
|
+
|
|
2012
|
+
it('does not restore transcription subscription when caption intent is disabled', () => {
|
|
2013
|
+
webex.internal.voicea.getIsCaptionBoxOn.returns(false);
|
|
2014
|
+
|
|
2015
|
+
meeting.handleLLMOnline();
|
|
2016
|
+
|
|
2017
|
+
assert.notCalled(webex.internal.voicea.updateSubchannelSubscriptions);
|
|
2018
|
+
});
|
|
1983
2019
|
});
|
|
1984
2020
|
|
|
1985
2021
|
describe('#join', () => {
|
|
@@ -1999,6 +2035,7 @@ describe('plugin-meetings', () => {
|
|
|
1999
2035
|
it('should have #join', () => {
|
|
2000
2036
|
assert.exists(meeting.join);
|
|
2001
2037
|
});
|
|
2038
|
+
|
|
2002
2039
|
beforeEach(() => {
|
|
2003
2040
|
setCorrelationIdSpy = sinon.spy(meeting, 'setCorrelationId');
|
|
2004
2041
|
meeting.setLocus = sinon.stub().returns(true);
|
|
@@ -2152,7 +2189,6 @@ describe('plugin-meetings', () => {
|
|
|
2152
2189
|
await meeting.join().catch(() => {
|
|
2153
2190
|
assert.calledOnce(MeetingUtil.joinMeeting);
|
|
2154
2191
|
|
|
2155
|
-
// Assert that client.locus.join.response error event is not sent from this function, it is now emitted from MeetingUtil.joinMeeting
|
|
2156
2192
|
assert.calledOnce(webex.internal.newMetrics.submitClientEvent);
|
|
2157
2193
|
assert.calledWithMatch(webex.internal.newMetrics.submitClientEvent, {
|
|
2158
2194
|
name: 'client.call.initiated',
|
|
@@ -2184,6 +2220,7 @@ describe('plugin-meetings', () => {
|
|
|
2184
2220
|
});
|
|
2185
2221
|
});
|
|
2186
2222
|
});
|
|
2223
|
+
|
|
2187
2224
|
describe('lmm, transcription & permissionTokenRefresh decoupling', () => {
|
|
2188
2225
|
beforeEach(() => {
|
|
2189
2226
|
sandbox.stub(MeetingUtil, 'joinMeeting').returns(Promise.resolve(joinMeetingResult));
|
|
@@ -2254,7 +2291,6 @@ describe('plugin-meetings', () => {
|
|
|
2254
2291
|
const locusInfoParseStub = sinon.stub(meeting.locusInfo, 'parse');
|
|
2255
2292
|
sinon.stub(meeting, 'isJoined').returns(true);
|
|
2256
2293
|
|
|
2257
|
-
// Set up llm.on stub to capture the registered listener when updateLLMConnection is called
|
|
2258
2294
|
let locusLLMEventListener;
|
|
2259
2295
|
meeting.webex.internal.llm.on = sinon.stub().callsFake((eventName, callback) => {
|
|
2260
2296
|
if (eventName === 'event:locus.state_message') {
|
|
@@ -2263,16 +2299,12 @@ describe('plugin-meetings', () => {
|
|
|
2263
2299
|
});
|
|
2264
2300
|
meeting.webex.internal.llm.off = sinon.stub();
|
|
2265
2301
|
|
|
2266
|
-
// we need the real meeting.updateLLMConnection not the mock
|
|
2267
2302
|
meeting.updateLLMConnection.restore();
|
|
2268
2303
|
|
|
2269
|
-
// Call updateLLMConnection to register the listener
|
|
2270
2304
|
await meeting.updateLLMConnection();
|
|
2271
2305
|
|
|
2272
|
-
// Verify the listener was registered and we captured it
|
|
2273
2306
|
assert.isDefined(locusLLMEventListener, 'LLM event listener should be registered');
|
|
2274
2307
|
|
|
2275
|
-
// Now trigger the event
|
|
2276
2308
|
const eventData = {
|
|
2277
2309
|
eventType: 'locus.state_message',
|
|
2278
2310
|
stateElementsMessage: {
|
|
@@ -2292,13 +2324,10 @@ describe('plugin-meetings', () => {
|
|
|
2292
2324
|
sinon.stub(meeting.webex.internal.llm, 'hasEverConnected').value(true);
|
|
2293
2325
|
sinon.stub(meeting.webex.internal.llm, 'registerAndConnect').resolves({});
|
|
2294
2326
|
|
|
2295
|
-
// Restore the real updateLLMConnection
|
|
2296
2327
|
meeting.updateLLMConnection.restore();
|
|
2297
2328
|
|
|
2298
|
-
// Call updateLLMConnection to start the timer
|
|
2299
2329
|
await meeting.updateLLMConnection();
|
|
2300
2330
|
|
|
2301
|
-
// Fast forward time by 3 minutes
|
|
2302
2331
|
fakeClock.tick(3 * 60 * 1000);
|
|
2303
2332
|
|
|
2304
2333
|
assert.calledWith(
|
|
@@ -2323,18 +2352,14 @@ describe('plugin-meetings', () => {
|
|
|
2323
2352
|
.stub(meeting.webex.internal.llm, 'getDatachannelUrl')
|
|
2324
2353
|
.returns('https://datachannel1.example.com');
|
|
2325
2354
|
|
|
2326
|
-
// Restore the real updateLLMConnection
|
|
2327
2355
|
meeting.updateLLMConnection.restore();
|
|
2328
2356
|
|
|
2329
|
-
// First, connect LLM and start the timer
|
|
2330
2357
|
isJoinedStub.returns(true);
|
|
2331
2358
|
meeting.webex.internal.llm.isConnected.returns(false);
|
|
2332
2359
|
await meeting.updateLLMConnection();
|
|
2333
2360
|
|
|
2334
|
-
// Verify timer was started
|
|
2335
2361
|
assert.exists(meeting.llmHealthCheckTimer);
|
|
2336
2362
|
|
|
2337
|
-
// Now simulate that we're no longer joined
|
|
2338
2363
|
isJoinedStub.returns(false);
|
|
2339
2364
|
meeting.webex.internal.llm.isConnected.returns(true);
|
|
2340
2365
|
|
|
@@ -2342,10 +2367,8 @@ describe('plugin-meetings', () => {
|
|
|
2342
2367
|
|
|
2343
2368
|
assert.calledOnce(meeting.webex.internal.llm.disconnectLLM);
|
|
2344
2369
|
|
|
2345
|
-
// Verify the timer was cleared (should be undefined)
|
|
2346
2370
|
assert.isUndefined(meeting.llmHealthCheckTimer);
|
|
2347
2371
|
|
|
2348
|
-
// Fast forward time to ensure no metric is sent
|
|
2349
2372
|
Metrics.sendBehavioralMetric.resetHistory();
|
|
2350
2373
|
fakeClock.tick(3 * 60 * 1000);
|
|
2351
2374
|
|
|
@@ -2380,7 +2403,6 @@ describe('plugin-meetings', () => {
|
|
|
2380
2403
|
.stub()
|
|
2381
2404
|
.rejects(new CaptchaError('bad captcha'));
|
|
2382
2405
|
const stateMachineFailSpy = sinon.spy(meeting.meetingFiniteStateMachine, 'fail');
|
|
2383
|
-
const joinMeetingOptionsSpy = sinon.spy(MeetingUtil, 'joinMeetingOptions');
|
|
2384
2406
|
|
|
2385
2407
|
try {
|
|
2386
2408
|
await meeting.join();
|
|
@@ -2394,8 +2416,7 @@ describe('plugin-meetings', () => {
|
|
|
2394
2416
|
);
|
|
2395
2417
|
assert.instanceOf(error, CaptchaError);
|
|
2396
2418
|
assert.equal(error.message, 'bad captcha');
|
|
2397
|
-
|
|
2398
|
-
assert.notCalled(joinMeetingOptionsSpy);
|
|
2419
|
+
assert.notCalled(MeetingUtil.joinMeeting);
|
|
2399
2420
|
}
|
|
2400
2421
|
});
|
|
2401
2422
|
|
|
@@ -2404,7 +2425,6 @@ describe('plugin-meetings', () => {
|
|
|
2404
2425
|
.stub()
|
|
2405
2426
|
.rejects(new PasswordError('bad password'));
|
|
2406
2427
|
const stateMachineFailSpy = sinon.spy(meeting.meetingFiniteStateMachine, 'fail');
|
|
2407
|
-
const joinMeetingOptionsSpy = sinon.spy(MeetingUtil.joinMeetingOptions);
|
|
2408
2428
|
|
|
2409
2429
|
try {
|
|
2410
2430
|
await meeting.join();
|
|
@@ -2418,8 +2438,7 @@ describe('plugin-meetings', () => {
|
|
|
2418
2438
|
);
|
|
2419
2439
|
assert.instanceOf(error, PasswordError);
|
|
2420
2440
|
assert.equal(error.message, 'bad password');
|
|
2421
|
-
|
|
2422
|
-
assert.notCalled(joinMeetingOptionsSpy);
|
|
2441
|
+
assert.notCalled(MeetingUtil.joinMeeting);
|
|
2423
2442
|
}
|
|
2424
2443
|
});
|
|
2425
2444
|
|
|
@@ -2428,7 +2447,6 @@ describe('plugin-meetings', () => {
|
|
|
2428
2447
|
.stub()
|
|
2429
2448
|
.rejects(new PermissionError('bad permission'));
|
|
2430
2449
|
const stateMachineFailSpy = sinon.spy(meeting.meetingFiniteStateMachine, 'fail');
|
|
2431
|
-
const joinMeetingOptionsSpy = sinon.spy(MeetingUtil.joinMeetingOptions);
|
|
2432
2450
|
|
|
2433
2451
|
try {
|
|
2434
2452
|
await meeting.join();
|
|
@@ -2442,14 +2460,14 @@ describe('plugin-meetings', () => {
|
|
|
2442
2460
|
);
|
|
2443
2461
|
assert.instanceOf(error, PermissionError);
|
|
2444
2462
|
assert.equal(error.message, 'bad permission');
|
|
2445
|
-
|
|
2446
|
-
assert.notCalled(joinMeetingOptionsSpy);
|
|
2463
|
+
assert.notCalled(MeetingUtil.joinMeeting);
|
|
2447
2464
|
}
|
|
2448
2465
|
});
|
|
2449
2466
|
});
|
|
2450
2467
|
});
|
|
2451
2468
|
});
|
|
2452
2469
|
|
|
2470
|
+
|
|
2453
2471
|
describe('#addMedia', () => {
|
|
2454
2472
|
const muteStateStub = {
|
|
2455
2473
|
handleClientRequest: sinon.stub().returns(Promise.resolve(true)),
|
|
@@ -9198,8 +9216,8 @@ describe('plugin-meetings', () => {
|
|
|
9198
9216
|
const fakeMultistreamRoapMediaConnection = {
|
|
9199
9217
|
createSendSlot: () => {
|
|
9200
9218
|
return {
|
|
9201
|
-
|
|
9202
|
-
|
|
9219
|
+
setCustomCodecParameters: sinon.stub().resolves(),
|
|
9220
|
+
markCustomCodecParametersForDeletion: sinon.stub().resolves(),
|
|
9203
9221
|
};
|
|
9204
9222
|
},
|
|
9205
9223
|
};
|
|
@@ -9222,27 +9240,29 @@ describe('plugin-meetings', () => {
|
|
|
9222
9240
|
}
|
|
9223
9241
|
);
|
|
9224
9242
|
|
|
9225
|
-
it('should set
|
|
9243
|
+
it('should set custom codec parameters when shouldEnableMusicMode is true', async () => {
|
|
9226
9244
|
await meeting.enableMusicMode(true);
|
|
9227
9245
|
assert.calledOnceWithExactly(
|
|
9228
|
-
meeting.sendSlotManager.getSlot(MediaType.AudioMain).
|
|
9246
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).setCustomCodecParameters,
|
|
9247
|
+
MediaCodecMimeType.OPUS,
|
|
9229
9248
|
{
|
|
9230
9249
|
maxaveragebitrate: '64000',
|
|
9231
9250
|
maxplaybackrate: '48000',
|
|
9232
9251
|
}
|
|
9233
9252
|
);
|
|
9234
9253
|
assert.notCalled(
|
|
9235
|
-
meeting.sendSlotManager.getSlot(MediaType.AudioMain).
|
|
9254
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).markCustomCodecParametersForDeletion
|
|
9236
9255
|
);
|
|
9237
9256
|
});
|
|
9238
9257
|
|
|
9239
|
-
it('should
|
|
9258
|
+
it('should mark custom codec parameters for deletion when shouldEnableMusicMode is false', async () => {
|
|
9240
9259
|
await meeting.enableMusicMode(false);
|
|
9241
9260
|
assert.calledOnceWithExactly(
|
|
9242
|
-
meeting.sendSlotManager.getSlot(MediaType.AudioMain).
|
|
9261
|
+
meeting.sendSlotManager.getSlot(MediaType.AudioMain).markCustomCodecParametersForDeletion,
|
|
9262
|
+
MediaCodecMimeType.OPUS,
|
|
9243
9263
|
['maxaveragebitrate', 'maxplaybackrate']
|
|
9244
9264
|
);
|
|
9245
|
-
assert.notCalled(meeting.sendSlotManager.getSlot(MediaType.AudioMain).
|
|
9265
|
+
assert.notCalled(meeting.sendSlotManager.getSlot(MediaType.AudioMain).setCustomCodecParameters);
|
|
9246
9266
|
});
|
|
9247
9267
|
});
|
|
9248
9268
|
|
|
@@ -10397,14 +10417,24 @@ describe('plugin-meetings', () => {
|
|
|
10397
10417
|
);
|
|
10398
10418
|
done();
|
|
10399
10419
|
});
|
|
10400
|
-
it('listens to the self admitted guest event', (
|
|
10420
|
+
it('listens to the self admitted guest event without blocking on token prefetch', async () => {
|
|
10401
10421
|
meeting.stopKeepAlive = sinon.stub();
|
|
10402
10422
|
meeting.updateLLMConnection = sinon.stub();
|
|
10423
|
+
let resolvePrefetch;
|
|
10424
|
+
|
|
10425
|
+
meeting.ensureDefaultDatachannelTokenAfterAdmit = sinon
|
|
10426
|
+
.stub()
|
|
10427
|
+
.returns(new Promise((resolve) => {
|
|
10428
|
+
resolvePrefetch = resolve;
|
|
10429
|
+
}));
|
|
10403
10430
|
meeting.rtcMetrics = {
|
|
10404
10431
|
sendNextMetrics: sinon.stub(),
|
|
10405
10432
|
};
|
|
10433
|
+
|
|
10406
10434
|
meeting.locusInfo.emit({function: 'test', file: 'test'}, 'SELF_ADMITTED_GUEST', test1);
|
|
10435
|
+
|
|
10407
10436
|
assert.calledOnceWithExactly(meeting.stopKeepAlive);
|
|
10437
|
+
assert.calledOnceWithExactly(meeting.ensureDefaultDatachannelTokenAfterAdmit);
|
|
10408
10438
|
assert.calledThrice(TriggerProxy.trigger);
|
|
10409
10439
|
assert.calledWith(
|
|
10410
10440
|
TriggerProxy.trigger,
|
|
@@ -10423,7 +10453,11 @@ describe('plugin-meetings', () => {
|
|
|
10423
10453
|
correlation_id: meeting.correlationId,
|
|
10424
10454
|
}
|
|
10425
10455
|
);
|
|
10426
|
-
|
|
10456
|
+
|
|
10457
|
+
resolvePrefetch(false);
|
|
10458
|
+
await Promise.resolve();
|
|
10459
|
+
|
|
10460
|
+
assert.calledOnce(meeting.updateLLMConnection);
|
|
10427
10461
|
});
|
|
10428
10462
|
|
|
10429
10463
|
it('listens to the breakouts changed event', () => {
|
|
@@ -12745,6 +12779,93 @@ describe('plugin-meetings', () => {
|
|
|
12745
12779
|
});
|
|
12746
12780
|
});
|
|
12747
12781
|
|
|
12782
|
+
describe('#saveDataChannelToken', () => {
|
|
12783
|
+
beforeEach(() => {
|
|
12784
|
+
webex.internal.llm.setDatachannelToken = sinon.stub();
|
|
12785
|
+
});
|
|
12786
|
+
|
|
12787
|
+
it('saves datachannelToken into LLM as Default', () => {
|
|
12788
|
+
meeting.saveDataChannelToken({
|
|
12789
|
+
locus: {
|
|
12790
|
+
self: {datachannelToken: 'default-token'},
|
|
12791
|
+
},
|
|
12792
|
+
});
|
|
12793
|
+
|
|
12794
|
+
assert.calledWithExactly(
|
|
12795
|
+
webex.internal.llm.setDatachannelToken,
|
|
12796
|
+
'default-token',
|
|
12797
|
+
'llm-default-session'
|
|
12798
|
+
);
|
|
12799
|
+
});
|
|
12800
|
+
|
|
12801
|
+
it('saves practiceSessionDatachannelToken into LLM as PracticeSession', () => {
|
|
12802
|
+
meeting.saveDataChannelToken({
|
|
12803
|
+
locus: {
|
|
12804
|
+
self: {practiceSessionDatachannelToken: 'ps-token'},
|
|
12805
|
+
},
|
|
12806
|
+
});
|
|
12807
|
+
|
|
12808
|
+
assert.calledWithExactly(
|
|
12809
|
+
webex.internal.llm.setDatachannelToken,
|
|
12810
|
+
'ps-token',
|
|
12811
|
+
'llm-practice-session'
|
|
12812
|
+
);
|
|
12813
|
+
});
|
|
12814
|
+
|
|
12815
|
+
it('saves both tokens when both are present', () => {
|
|
12816
|
+
meeting.saveDataChannelToken({
|
|
12817
|
+
locus: {
|
|
12818
|
+
self: {
|
|
12819
|
+
datachannelToken: 'default-token',
|
|
12820
|
+
practiceSessionDatachannelToken: 'ps-token',
|
|
12821
|
+
},
|
|
12822
|
+
},
|
|
12823
|
+
});
|
|
12824
|
+
|
|
12825
|
+
assert.calledTwice(webex.internal.llm.setDatachannelToken);
|
|
12826
|
+
assert.calledWithExactly(
|
|
12827
|
+
webex.internal.llm.setDatachannelToken,
|
|
12828
|
+
'default-token',
|
|
12829
|
+
'llm-default-session'
|
|
12830
|
+
);
|
|
12831
|
+
assert.calledWithExactly(
|
|
12832
|
+
webex.internal.llm.setDatachannelToken,
|
|
12833
|
+
'ps-token',
|
|
12834
|
+
'llm-practice-session'
|
|
12835
|
+
);
|
|
12836
|
+
});
|
|
12837
|
+
|
|
12838
|
+
it('does not call setDatachannelToken when no tokens are present', () => {
|
|
12839
|
+
meeting.saveDataChannelToken({locus: {self: {}}});
|
|
12840
|
+
|
|
12841
|
+
assert.notCalled(webex.internal.llm.setDatachannelToken);
|
|
12842
|
+
});
|
|
12843
|
+
|
|
12844
|
+
it('handles undefined join gracefully', () => {
|
|
12845
|
+
meeting.saveDataChannelToken(undefined);
|
|
12846
|
+
|
|
12847
|
+
assert.notCalled(webex.internal.llm.setDatachannelToken);
|
|
12848
|
+
});
|
|
12849
|
+
|
|
12850
|
+
it('handles missing locus.self gracefully', () => {
|
|
12851
|
+
meeting.saveDataChannelToken({locus: {}});
|
|
12852
|
+
|
|
12853
|
+
assert.notCalled(webex.internal.llm.setDatachannelToken);
|
|
12854
|
+
});
|
|
12855
|
+
});
|
|
12856
|
+
|
|
12857
|
+
describe('#clearDataChannelToken', () => {
|
|
12858
|
+
beforeEach(() => {
|
|
12859
|
+
webex.internal.llm.resetDatachannelTokens = sinon.stub();
|
|
12860
|
+
});
|
|
12861
|
+
|
|
12862
|
+
it('calls resetDatachannelTokens on LLM', () => {
|
|
12863
|
+
meeting.clearDataChannelToken();
|
|
12864
|
+
|
|
12865
|
+
assert.calledOnce(webex.internal.llm.resetDatachannelTokens);
|
|
12866
|
+
});
|
|
12867
|
+
});
|
|
12868
|
+
|
|
12748
12869
|
describe('#updateLLMConnection', () => {
|
|
12749
12870
|
beforeEach(() => {
|
|
12750
12871
|
webex.internal.llm.isConnected = sinon.stub().returns(false);
|
|
@@ -13011,15 +13132,14 @@ describe('plugin-meetings', () => {
|
|
|
13011
13132
|
undefined
|
|
13012
13133
|
);
|
|
13013
13134
|
});
|
|
13014
|
-
it('passes dataChannelToken to registerAndConnect', async () => {
|
|
13135
|
+
it('passes dataChannelToken from LLM to registerAndConnect', async () => {
|
|
13015
13136
|
meeting.joinedWith = {state: 'JOINED'};
|
|
13016
13137
|
meeting.locusInfo = {
|
|
13017
13138
|
url: 'a url',
|
|
13018
13139
|
info: {datachannelUrl: 'a datachannel url'},
|
|
13019
|
-
self: {datachannelToken: 'token-123'},
|
|
13020
13140
|
};
|
|
13021
13141
|
|
|
13022
|
-
webex.internal.llm.getDatachannelToken.returns(
|
|
13142
|
+
webex.internal.llm.getDatachannelToken.withArgs('llm-default-session').returns('token-123');
|
|
13023
13143
|
|
|
13024
13144
|
await meeting.updateLLMConnection();
|
|
13025
13145
|
|
|
@@ -13029,17 +13149,16 @@ describe('plugin-meetings', () => {
|
|
|
13029
13149
|
'a datachannel url',
|
|
13030
13150
|
'token-123'
|
|
13031
13151
|
);
|
|
13032
|
-
assert.
|
|
13152
|
+
assert.notCalled(webex.internal.llm.setDatachannelToken);
|
|
13033
13153
|
});
|
|
13034
|
-
it('
|
|
13154
|
+
it('passes undefined token when LLM has no token stored', async () => {
|
|
13035
13155
|
meeting.joinedWith = {state: 'JOINED'};
|
|
13036
13156
|
meeting.locusInfo = {
|
|
13037
13157
|
url: 'a url',
|
|
13038
13158
|
info: {datachannelUrl: 'a datachannel url'},
|
|
13039
|
-
self: {datachannelToken: 'locus-token'},
|
|
13040
13159
|
};
|
|
13041
13160
|
|
|
13042
|
-
webex.internal.llm.getDatachannelToken.
|
|
13161
|
+
webex.internal.llm.getDatachannelToken.returns(undefined);
|
|
13043
13162
|
|
|
13044
13163
|
await meeting.updateLLMConnection();
|
|
13045
13164
|
|
|
@@ -13047,7 +13166,7 @@ describe('plugin-meetings', () => {
|
|
|
13047
13166
|
webex.internal.llm.registerAndConnect,
|
|
13048
13167
|
'a url',
|
|
13049
13168
|
'a datachannel url',
|
|
13050
|
-
|
|
13169
|
+
undefined
|
|
13051
13170
|
);
|
|
13052
13171
|
|
|
13053
13172
|
assert.notCalled(webex.internal.llm.setDatachannelToken);
|
|
@@ -13058,7 +13177,6 @@ describe('plugin-meetings', () => {
|
|
|
13058
13177
|
meeting.locusInfo = {
|
|
13059
13178
|
url: 'a url',
|
|
13060
13179
|
info: {datachannelUrl: 'a datachannel url'},
|
|
13061
|
-
self: {datachannelToken: 'token-123'},
|
|
13062
13180
|
};
|
|
13063
13181
|
|
|
13064
13182
|
webex.internal.llm.getDatachannelToken.returns(undefined);
|
|
@@ -13070,9 +13188,9 @@ describe('plugin-meetings', () => {
|
|
|
13070
13188
|
webex.internal.llm.registerAndConnect,
|
|
13071
13189
|
'a url',
|
|
13072
13190
|
'a datachannel url',
|
|
13073
|
-
|
|
13191
|
+
undefined
|
|
13074
13192
|
);
|
|
13075
|
-
assert.
|
|
13193
|
+
assert.notCalled(webex.internal.llm.setDatachannelToken);
|
|
13076
13194
|
});
|
|
13077
13195
|
|
|
13078
13196
|
describe('#clearMeetingData', () => {
|
|
@@ -13083,7 +13201,7 @@ describe('plugin-meetings', () => {
|
|
|
13083
13201
|
meeting.annotation.deregisterEvents = sinon.stub();
|
|
13084
13202
|
meeting.clearLLMHealthCheckTimer = sinon.stub();
|
|
13085
13203
|
meeting.stopTranscription = sinon.stub();
|
|
13086
|
-
meeting.
|
|
13204
|
+
meeting.clearDataChannelToken = sinon.stub();
|
|
13087
13205
|
meeting.shareStatus = 'no-share';
|
|
13088
13206
|
});
|
|
13089
13207
|
|
|
@@ -13107,6 +13225,8 @@ describe('plugin-meetings', () => {
|
|
|
13107
13225
|
);
|
|
13108
13226
|
assert.calledOnce(meeting.clearLLMHealthCheckTimer);
|
|
13109
13227
|
assert.calledOnce(meeting.stopTranscription);
|
|
13228
|
+
assert.isUndefined(meeting.transcription);
|
|
13229
|
+
assert.calledOnce(meeting.clearDataChannelToken);
|
|
13110
13230
|
assert.calledOnce(meeting.annotation.deregisterEvents);
|
|
13111
13231
|
});
|
|
13112
13232
|
it('continues cleanup when disconnectLLM fails during meeting data cleanup', async () => {
|
|
@@ -13127,8 +13247,19 @@ describe('plugin-meetings', () => {
|
|
|
13127
13247
|
);
|
|
13128
13248
|
assert.calledOnce(meeting.clearLLMHealthCheckTimer);
|
|
13129
13249
|
assert.calledOnce(meeting.stopTranscription);
|
|
13250
|
+
assert.isUndefined(meeting.transcription);
|
|
13251
|
+
assert.calledOnce(meeting.clearDataChannelToken);
|
|
13130
13252
|
assert.calledOnce(meeting.annotation.deregisterEvents);
|
|
13131
13253
|
});
|
|
13254
|
+
it('always calls stopTranscription even when transcription is undefined', async () => {
|
|
13255
|
+
meeting.transcription = undefined;
|
|
13256
|
+
|
|
13257
|
+
await meeting.clearMeetingData();
|
|
13258
|
+
|
|
13259
|
+
assert.calledOnce(meeting.stopTranscription);
|
|
13260
|
+
assert.isUndefined(meeting.transcription);
|
|
13261
|
+
assert.calledOnce(meeting.clearDataChannelToken);
|
|
13262
|
+
});
|
|
13132
13263
|
});
|
|
13133
13264
|
});
|
|
13134
13265
|
|
|
@@ -1285,10 +1285,10 @@ describe('plugin-meetings', () => {
|
|
|
1285
1285
|
assert.exists(result.dispose);
|
|
1286
1286
|
});
|
|
1287
1287
|
|
|
1288
|
-
it('creates noise reduction effect with
|
|
1288
|
+
it('creates noise reduction effect with OFMV model', async () => {
|
|
1289
1289
|
const result = await webex.meetings.createNoiseReductionEffect({
|
|
1290
1290
|
audioContext: {},
|
|
1291
|
-
model: '
|
|
1291
|
+
model: 'ofmv',
|
|
1292
1292
|
});
|
|
1293
1293
|
|
|
1294
1294
|
assert.exists(result);
|
|
@@ -1300,7 +1300,7 @@ describe('plugin-meetings', () => {
|
|
|
1300
1300
|
authToken: 'fake_token',
|
|
1301
1301
|
mode: 'WORKLET',
|
|
1302
1302
|
avoidSimd: false,
|
|
1303
|
-
model: '
|
|
1303
|
+
model: 'ofmv',
|
|
1304
1304
|
});
|
|
1305
1305
|
assert.exists(result.enable);
|
|
1306
1306
|
assert.exists(result.disable);
|