@stream-io/video-client 1.50.0 → 1.51.0
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/CHANGELOG.md +11 -0
- package/dist/index.browser.es.js +288 -58
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +288 -58
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +288 -58
- package/dist/index.es.js.map +1 -1
- package/dist/src/Call.d.ts +1 -0
- package/dist/src/devices/CameraManager.d.ts +1 -0
- package/dist/src/devices/DeviceManager.d.ts +20 -0
- package/dist/src/devices/VirtualDevice.d.ts +59 -0
- package/dist/src/devices/devicePersistence.d.ts +1 -1
- package/dist/src/devices/index.d.ts +1 -0
- package/dist/src/rtc/BasePeerConnection.d.ts +7 -2
- package/dist/src/rtc/Publisher.d.ts +21 -3
- package/dist/src/rtc/TransceiverCache.d.ts +5 -1
- package/dist/src/rtc/helpers/degradationPreference.d.ts +1 -0
- package/dist/src/rtc/types.d.ts +2 -0
- package/package.json +2 -2
- package/src/Call.ts +22 -11
- package/src/devices/CameraManager.ts +9 -2
- package/src/devices/DeviceManager.ts +148 -8
- package/src/devices/DeviceManagerState.ts +4 -1
- package/src/devices/VirtualDevice.ts +69 -0
- package/src/devices/__tests__/CameraManager.test.ts +19 -0
- package/src/devices/__tests__/DeviceManager.test.ts +121 -1
- package/src/devices/devicePersistence.ts +2 -1
- package/src/devices/index.ts +1 -0
- package/src/rtc/BasePeerConnection.ts +15 -3
- package/src/rtc/Publisher.ts +140 -41
- package/src/rtc/TransceiverCache.ts +10 -3
- package/src/rtc/__tests__/Call.reconnect.test.ts +121 -2
- package/src/rtc/__tests__/Publisher.test.ts +659 -112
- package/src/rtc/__tests__/Subscriber.test.ts +2 -2
- package/src/rtc/helpers/__tests__/degradationPreference.test.ts +33 -1
- package/src/rtc/helpers/degradationPreference.ts +18 -0
- package/src/rtc/types.ts +2 -0
|
@@ -43,7 +43,7 @@ const makeCall = () => {
|
|
|
43
43
|
*/
|
|
44
44
|
const primeForReconnect = (call: Call) => {
|
|
45
45
|
// put the call in a non-terminal, non-JOINED state so the do-while iterates
|
|
46
|
-
call.state.setCallingState(CallingState.
|
|
46
|
+
call.state.setCallingState(CallingState.IDLE);
|
|
47
47
|
// force the strategy-decider in the catch block to always pick REJOIN,
|
|
48
48
|
// so tests that care about the rejoin rate limiter don't bounce to FAST
|
|
49
49
|
// based on wall-clock timing. Individual tests that want to exercise the
|
|
@@ -136,7 +136,7 @@ describe('Call reconnect stopping conditions', () => {
|
|
|
136
136
|
});
|
|
137
137
|
|
|
138
138
|
for (let i = 0; i < 5; i++) {
|
|
139
|
-
call.state.setCallingState(CallingState.
|
|
139
|
+
call.state.setCallingState(CallingState.IDLE);
|
|
140
140
|
await call['reconnect'](WebsocketReconnectStrategy.FAST, 'test');
|
|
141
141
|
}
|
|
142
142
|
|
|
@@ -404,6 +404,125 @@ describe('Call reconnect stopping conditions', () => {
|
|
|
404
404
|
});
|
|
405
405
|
});
|
|
406
406
|
|
|
407
|
+
/**
|
|
408
|
+
* Entry-condition bails. `reconnect()` must drop new triggers when:
|
|
409
|
+
* - A join/reconnect/migrate lifecycle is already in progress.
|
|
410
|
+
* - A reconnect is already queued via `hasPending(reconnectConcurrencyTag)`.
|
|
411
|
+
* - The terminal `RECONNECTING_FAILED` state has been reached.
|
|
412
|
+
*
|
|
413
|
+
* These are pure short-circuits — none of the strategy implementations
|
|
414
|
+
* should be invoked.
|
|
415
|
+
*/
|
|
416
|
+
describe('Call reconnect entry-condition bails', () => {
|
|
417
|
+
let call: Call;
|
|
418
|
+
|
|
419
|
+
beforeEach(() => {
|
|
420
|
+
call = makeCall();
|
|
421
|
+
vi.spyOn(connectionUtils, 'sleep').mockResolvedValue(undefined);
|
|
422
|
+
vi.spyOn(call, 'leave').mockResolvedValue(undefined);
|
|
423
|
+
vi.spyOn(call, 'get').mockResolvedValue({} as never);
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
afterEach(() => {
|
|
427
|
+
vi.clearAllMocks();
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
const stubAllStrategies = () => ({
|
|
431
|
+
fast: vi
|
|
432
|
+
.spyOn(
|
|
433
|
+
call as unknown as { reconnectFast: () => Promise<void> },
|
|
434
|
+
'reconnectFast',
|
|
435
|
+
)
|
|
436
|
+
.mockResolvedValue(undefined),
|
|
437
|
+
rejoin: vi
|
|
438
|
+
.spyOn(
|
|
439
|
+
call as unknown as { reconnectRejoin: () => Promise<void> },
|
|
440
|
+
'reconnectRejoin',
|
|
441
|
+
)
|
|
442
|
+
.mockResolvedValue(undefined),
|
|
443
|
+
migrate: vi
|
|
444
|
+
.spyOn(
|
|
445
|
+
call as unknown as { reconnectMigrate: () => Promise<void> },
|
|
446
|
+
'reconnectMigrate',
|
|
447
|
+
)
|
|
448
|
+
.mockResolvedValue(undefined),
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
it('bails immediately when state is JOINING — Call.join owns recovery during the initial join window', async () => {
|
|
452
|
+
const strategies = stubAllStrategies();
|
|
453
|
+
call.state.setCallingState(CallingState.JOINING);
|
|
454
|
+
|
|
455
|
+
await call['reconnect'](WebsocketReconnectStrategy.REJOIN, 'test');
|
|
456
|
+
|
|
457
|
+
expect(strategies.fast).not.toHaveBeenCalled();
|
|
458
|
+
expect(strategies.rejoin).not.toHaveBeenCalled();
|
|
459
|
+
expect(strategies.migrate).not.toHaveBeenCalled();
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
it('bails immediately when state is RECONNECTING — another reconnect is already running', async () => {
|
|
463
|
+
const strategies = stubAllStrategies();
|
|
464
|
+
call.state.setCallingState(CallingState.RECONNECTING);
|
|
465
|
+
|
|
466
|
+
await call['reconnect'](WebsocketReconnectStrategy.REJOIN, 'test');
|
|
467
|
+
|
|
468
|
+
expect(strategies.fast).not.toHaveBeenCalled();
|
|
469
|
+
expect(strategies.rejoin).not.toHaveBeenCalled();
|
|
470
|
+
expect(strategies.migrate).not.toHaveBeenCalled();
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
it('bails immediately when state is MIGRATING — reconnectMigrate is in flight', async () => {
|
|
474
|
+
const strategies = stubAllStrategies();
|
|
475
|
+
call.state.setCallingState(CallingState.MIGRATING);
|
|
476
|
+
|
|
477
|
+
await call['reconnect'](WebsocketReconnectStrategy.REJOIN, 'test');
|
|
478
|
+
|
|
479
|
+
expect(strategies.fast).not.toHaveBeenCalled();
|
|
480
|
+
expect(strategies.rejoin).not.toHaveBeenCalled();
|
|
481
|
+
expect(strategies.migrate).not.toHaveBeenCalled();
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
it('bails immediately when state is RECONNECTING_FAILED — terminal, no further attempts', async () => {
|
|
485
|
+
const strategies = stubAllStrategies();
|
|
486
|
+
call.state.setCallingState(CallingState.RECONNECTING_FAILED);
|
|
487
|
+
|
|
488
|
+
await call['reconnect'](WebsocketReconnectStrategy.REJOIN, 'test');
|
|
489
|
+
|
|
490
|
+
expect(strategies.fast).not.toHaveBeenCalled();
|
|
491
|
+
expect(strategies.rejoin).not.toHaveBeenCalled();
|
|
492
|
+
expect(strategies.migrate).not.toHaveBeenCalled();
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
it('drops duplicate reconnect calls while one is already pending', async () => {
|
|
496
|
+
let resolveFirst: () => void = () => {};
|
|
497
|
+
const firstStrategy = new Promise<void>((resolve) => {
|
|
498
|
+
resolveFirst = resolve;
|
|
499
|
+
});
|
|
500
|
+
const rejoinSpy = vi
|
|
501
|
+
.spyOn(
|
|
502
|
+
call as unknown as { reconnectRejoin: () => Promise<void> },
|
|
503
|
+
'reconnectRejoin',
|
|
504
|
+
)
|
|
505
|
+
.mockImplementationOnce(async () => {
|
|
506
|
+
await firstStrategy;
|
|
507
|
+
call.state.setCallingState(CallingState.JOINED);
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
primeForReconnect(call);
|
|
511
|
+
|
|
512
|
+
const firstCall = call['reconnect'](
|
|
513
|
+
WebsocketReconnectStrategy.REJOIN,
|
|
514
|
+
'first',
|
|
515
|
+
);
|
|
516
|
+
await Promise.resolve();
|
|
517
|
+
call['reconnect'](WebsocketReconnectStrategy.REJOIN, 'second');
|
|
518
|
+
|
|
519
|
+
expect(rejoinSpy).toHaveBeenCalledTimes(1);
|
|
520
|
+
|
|
521
|
+
resolveFirst();
|
|
522
|
+
await firstCall;
|
|
523
|
+
});
|
|
524
|
+
});
|
|
525
|
+
|
|
407
526
|
/**
|
|
408
527
|
* End-to-end-ish wiring tests: simulate failures at the peer-connection layer
|
|
409
528
|
* and verify they propagate through `onReconnectionNeeded` → `Call.reconnect` →
|