livekit-client 2.22.0 → 2.22.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/livekit-client.e2ee.worker.js +1 -1
- package/dist/livekit-client.e2ee.worker.js.map +1 -1
- package/dist/livekit-client.e2ee.worker.mjs +187 -1
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +1764 -121
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.fm.worker.js +1 -1
- package/dist/livekit-client.fm.worker.js.map +1 -1
- package/dist/livekit-client.fm.worker.mjs +187 -1
- package/dist/livekit-client.fm.worker.mjs.map +1 -1
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/api/SignalClient.d.ts +25 -1
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/api/SignalClientStateMachine.d.ts +85 -0
- package/dist/src/api/SignalClientStateMachine.d.ts.map +1 -0
- package/dist/src/api/WebSocketStream.d.ts.map +1 -1
- package/dist/src/api/utils.d.ts.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/logger.d.ts +2 -1
- package/dist/src/logger.d.ts.map +1 -1
- package/dist/src/options.d.ts +22 -0
- package/dist/src/options.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +2 -1
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +7 -2
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +8 -1
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +1 -1
- package/dist/src/room/statsSummary.d.ts +13 -0
- package/dist/src/room/statsSummary.d.ts.map +1 -0
- package/dist/src/room/token-source/utils.d.ts.map +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts +10 -0
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/utils/machineInspector.d.ts +54 -0
- package/dist/src/utils/machineInspector.d.ts.map +1 -0
- package/dist/ts4.2/api/SignalClient.d.ts +25 -1
- package/dist/ts4.2/api/SignalClientStateMachine.d.ts +85 -0
- package/dist/ts4.2/index.d.ts +3 -2
- package/dist/ts4.2/logger.d.ts +2 -1
- package/dist/ts4.2/options.d.ts +22 -0
- package/dist/ts4.2/room/PCTransport.d.ts +2 -1
- package/dist/ts4.2/room/RTCEngine.d.ts +7 -2
- package/dist/ts4.2/room/Room.d.ts +8 -1
- package/dist/ts4.2/room/events.d.ts +1 -1
- package/dist/ts4.2/room/statsSummary.d.ts +13 -0
- package/dist/ts4.2/room/track/Track.d.ts +10 -0
- package/dist/ts4.2/utils/machineInspector.d.ts +54 -0
- package/package.json +7 -1
- package/src/api/SignalClient.test.ts +320 -8
- package/src/api/SignalClient.ts +260 -82
- package/src/api/SignalClientStateMachine.test.ts +472 -0
- package/src/api/SignalClientStateMachine.ts +180 -0
- package/src/api/WebSocketStream.ts +19 -3
- package/src/api/utils.test.ts +20 -1
- package/src/api/utils.ts +5 -0
- package/src/index.ts +5 -0
- package/src/logger.ts +1 -0
- package/src/options.ts +24 -0
- package/src/room/PCTransport.ts +2 -1
- package/src/room/RTCEngine.ts +16 -7
- package/src/room/Room.ts +70 -5
- package/src/room/events.ts +1 -1
- package/src/room/statsSummary.ts +187 -0
- package/src/room/token-source/test-tokens.ts +20 -0
- package/src/room/token-source/utils.test.ts +27 -0
- package/src/room/token-source/utils.ts +12 -5
- package/src/room/track/LocalAudioTrack.ts +9 -3
- package/src/room/track/Track.ts +27 -0
- package/src/room/utils.test.ts +24 -1
- package/src/room/utils.ts +1 -1
- package/src/utils/machineInspector.ts +90 -0
package/src/room/track/Track.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type { SignalClient } from '../../api/SignalClient';
|
|
|
11
11
|
import log, { LoggerNames, type StructuredLogger, getLogger } from '../../logger';
|
|
12
12
|
import type { NonSharedUint8Array } from '../../type-polyfills/non-shared-typed-arrays';
|
|
13
13
|
import { TrackEvent } from '../events';
|
|
14
|
+
import { summarizeStatsReport } from '../statsSummary';
|
|
14
15
|
import type { LoggerOptions } from '../types';
|
|
15
16
|
import { isFireFox, isSafari, isWeb } from '../utils';
|
|
16
17
|
import type { TrackProcessor } from './processor/types';
|
|
@@ -85,6 +86,8 @@ export abstract class Track<
|
|
|
85
86
|
|
|
86
87
|
protected monitorInterval?: ReturnType<typeof setInterval>;
|
|
87
88
|
|
|
89
|
+
private finalStatsLogged = false;
|
|
90
|
+
|
|
88
91
|
protected log: StructuredLogger = log;
|
|
89
92
|
|
|
90
93
|
protected constructor(
|
|
@@ -271,6 +274,11 @@ export abstract class Track<
|
|
|
271
274
|
/* @internal */
|
|
272
275
|
abstract startMonitor(signalClient?: SignalClient): void;
|
|
273
276
|
|
|
277
|
+
/**
|
|
278
|
+
* Raw stats of the sender or receiver this track is attached to.
|
|
279
|
+
*/
|
|
280
|
+
abstract getRTCStatsReport(): Promise<RTCStatsReport | undefined>;
|
|
281
|
+
|
|
274
282
|
/* @internal */
|
|
275
283
|
stopMonitor() {
|
|
276
284
|
if (this.monitorInterval) {
|
|
@@ -280,6 +288,25 @@ export abstract class Track<
|
|
|
280
288
|
cancelAnimationFrame(this.timeSyncHandle);
|
|
281
289
|
this.timeSyncHandle = undefined;
|
|
282
290
|
}
|
|
291
|
+
this.logFinalStats();
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Dumps the raw stats of the track as it ends, once: a track that stops
|
|
296
|
+
* between two of the room's stats dumps is gone by the time the next one runs.
|
|
297
|
+
*/
|
|
298
|
+
private logFinalStats() {
|
|
299
|
+
if (this.finalStatsLogged) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
this.finalStatsLogged = true;
|
|
303
|
+
this.getRTCStatsReport()
|
|
304
|
+
.then((report) => {
|
|
305
|
+
if (report) {
|
|
306
|
+
this.log.info('final track stats', summarizeStatsReport(report));
|
|
307
|
+
}
|
|
308
|
+
})
|
|
309
|
+
.catch((error) => this.log.debug('could not collect final track stats', { error }));
|
|
283
310
|
}
|
|
284
311
|
|
|
285
312
|
/** @internal */
|
package/src/room/utils.test.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { ClientInfo_Capability } from '@livekit/protocol';
|
|
2
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
3
3
|
import {
|
|
4
4
|
ddExtensionURI,
|
|
5
5
|
extractMaxAgeFromRequestHeaders,
|
|
6
6
|
getClientInfo,
|
|
7
7
|
negotiateDependencyDescriptor,
|
|
8
8
|
splitUtf8,
|
|
9
|
+
supportsAdaptiveStream,
|
|
9
10
|
toWebsocketUrl,
|
|
10
11
|
} from './utils';
|
|
11
12
|
|
|
@@ -257,3 +258,25 @@ describe('negotiateDependencyDescriptor', () => {
|
|
|
257
258
|
expect(negotiateDependencyDescriptor(transceiver)).toBe(false);
|
|
258
259
|
});
|
|
259
260
|
});
|
|
261
|
+
|
|
262
|
+
describe('supportsAdaptiveStream', () => {
|
|
263
|
+
afterEach(() => {
|
|
264
|
+
vi.unstubAllGlobals();
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('reports support where both observers exist', () => {
|
|
268
|
+
expect(supportsAdaptiveStream()).toBe(true);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('reports no support where ResizeObserver is missing', () => {
|
|
272
|
+
vi.stubGlobal('ResizeObserver', undefined);
|
|
273
|
+
|
|
274
|
+
expect(supportsAdaptiveStream()).toBe(false);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it('reports no support where IntersectionObserver is missing', () => {
|
|
278
|
+
vi.stubGlobal('IntersectionObserver', undefined);
|
|
279
|
+
|
|
280
|
+
expect(supportsAdaptiveStream()).toBe(false);
|
|
281
|
+
});
|
|
282
|
+
});
|
package/src/room/utils.ts
CHANGED
|
@@ -58,7 +58,7 @@ export function supportsAddTrack() {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
export function supportsAdaptiveStream() {
|
|
61
|
-
return typeof ResizeObserver !== undefined && typeof IntersectionObserver !== undefined;
|
|
61
|
+
return typeof ResizeObserver !== 'undefined' && typeof IntersectionObserver !== 'undefined';
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
export function supportsDynacast() {
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opt-in registry that lets a development tool observe the state machines driving the connection
|
|
3
|
+
* layer.
|
|
4
|
+
*
|
|
5
|
+
* The machines are private to the objects that own them and, more importantly, do not outlive them:
|
|
6
|
+
* a full reconnect replaces the whole engine along with its `SignalClient`, so anything watching a
|
|
7
|
+
* single machine reference goes blind exactly when the interesting part starts. Machines therefore
|
|
8
|
+
* announce themselves here as they are constructed, and a subscriber sees the whole succession.
|
|
9
|
+
*
|
|
10
|
+
* Nothing is recorded until {@link enableMachineInspector} is called, which no shipping code does —
|
|
11
|
+
* with the registry off, announcing is a comparison and a return.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The slice of machina's `Fsm` surface an inspector needs. Structural rather than machina's own
|
|
16
|
+
* type so that any machine satisfies it regardless of its state and input unions.
|
|
17
|
+
*/
|
|
18
|
+
export interface InspectableMachine {
|
|
19
|
+
readonly id: string;
|
|
20
|
+
readonly initialState: string;
|
|
21
|
+
readonly states: Record<string, Record<string, unknown>>;
|
|
22
|
+
readonly context?: unknown;
|
|
23
|
+
currentState(): string;
|
|
24
|
+
canHandle(input: string): boolean;
|
|
25
|
+
on(eventName: string, callback: (data: any) => void): { off(): void };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface MachineAnnouncement {
|
|
29
|
+
/** What the machine drives, e.g. `signal`. Not unique: each new `SignalClient` announces one. */
|
|
30
|
+
label: string;
|
|
31
|
+
/** How many machines have been announced before this one, so successive instances are tellable apart. */
|
|
32
|
+
seq: number;
|
|
33
|
+
/**
|
|
34
|
+
* When the machine was constructed. Carried on the announcement because subscribers receive the
|
|
35
|
+
* recorded ones on subscribe, and stamping those at replay time would date them all to whenever
|
|
36
|
+
* the tool happened to open.
|
|
37
|
+
*/
|
|
38
|
+
at: number;
|
|
39
|
+
machine: InspectableMachine;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Kept small: enough for a panel opened mid-session to see how the connection got where it is. */
|
|
43
|
+
const HISTORY_LIMIT = 16;
|
|
44
|
+
|
|
45
|
+
let enabled = false;
|
|
46
|
+
let announced: MachineAnnouncement[] = [];
|
|
47
|
+
let subscribers: Array<(announcement: MachineAnnouncement) => void> = [];
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Starts recording machine announcements. Call before the machines of interest are constructed —
|
|
51
|
+
* for the signal machine that means before the `Room` is created.
|
|
52
|
+
*/
|
|
53
|
+
export function enableMachineInspector() {
|
|
54
|
+
enabled = true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function isMachineInspectorEnabled() {
|
|
58
|
+
return enabled;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Announces a machine to whatever is watching. A no-op unless the inspector was enabled. */
|
|
62
|
+
export function announceMachine(label: string, machine: InspectableMachine) {
|
|
63
|
+
if (!enabled) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const announcement: MachineAnnouncement = {
|
|
67
|
+
label,
|
|
68
|
+
seq: announced.length,
|
|
69
|
+
at: Date.now(),
|
|
70
|
+
machine,
|
|
71
|
+
};
|
|
72
|
+
announced = [...announced.slice(-(HISTORY_LIMIT - 1)), announcement];
|
|
73
|
+
for (const subscriber of subscribers) {
|
|
74
|
+
subscriber(announcement);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Subscribes to machine announcements, replaying the ones already recorded so that a panel opened
|
|
80
|
+
* after connecting still sees the machine currently in charge. Returns an unsubscribe function.
|
|
81
|
+
*/
|
|
82
|
+
export function onMachineAnnounced(callback: (announcement: MachineAnnouncement) => void) {
|
|
83
|
+
subscribers = [...subscribers, callback];
|
|
84
|
+
for (const announcement of announced) {
|
|
85
|
+
callback(announcement);
|
|
86
|
+
}
|
|
87
|
+
return () => {
|
|
88
|
+
subscribers = subscribers.filter((subscriber) => subscriber !== callback);
|
|
89
|
+
};
|
|
90
|
+
}
|