livekit-client 1.9.2 → 1.9.4
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +2 -0
- package/dist/livekit-client.esm.mjs +8251 -8123
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/AsyncQueue.d.ts +23 -0
- package/dist/src/AsyncQueue.d.ts.map +1 -0
- package/dist/src/api/SignalClient.d.ts +98 -98
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/connectionHelper/ConnectionCheck.d.ts +25 -24
- package/dist/src/connectionHelper/ConnectionCheck.d.ts.map +1 -1
- package/dist/src/connectionHelper/checks/Checker.d.ts +58 -58
- package/dist/src/connectionHelper/checks/publishAudio.d.ts +5 -5
- package/dist/src/connectionHelper/checks/publishVideo.d.ts +5 -5
- package/dist/src/connectionHelper/checks/reconnect.d.ts +5 -5
- package/dist/src/connectionHelper/checks/turn.d.ts +5 -5
- package/dist/src/connectionHelper/checks/webrtc.d.ts +5 -5
- package/dist/src/connectionHelper/checks/websocket.d.ts +5 -5
- package/dist/src/index.d.ts +34 -31
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/logger.d.ts +25 -25
- package/dist/src/options.d.ts +98 -98
- package/dist/src/proto/google/protobuf/timestamp.d.ts +145 -145
- package/dist/src/proto/livekit_models.d.ts +2300 -2300
- package/dist/src/proto/livekit_rtc.d.ts +14032 -14032
- package/dist/src/room/DefaultReconnectPolicy.d.ts +7 -7
- package/dist/src/room/DeviceManager.d.ts +8 -8
- package/dist/src/room/PCTransport.d.ts +36 -37
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +126 -121
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/ReconnectPolicy.d.ts +23 -23
- package/dist/src/room/RegionUrlProvider.d.ts +13 -13
- package/dist/src/room/Room.d.ts +232 -232
- package/dist/src/room/defaults.d.ts +7 -7
- package/dist/src/room/defaults.d.ts.map +1 -1
- package/dist/src/room/errors.d.ts +42 -42
- package/dist/src/room/events.d.ts +455 -455
- package/dist/src/room/participant/LocalParticipant.d.ts +170 -170
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/Participant.d.ts +93 -93
- package/dist/src/room/participant/ParticipantTrackPermission.d.ts +25 -25
- package/dist/src/room/participant/RemoteParticipant.d.ts +52 -51
- package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/publishUtils.d.ts +19 -18
- package/dist/src/room/participant/publishUtils.d.ts.map +1 -1
- package/dist/src/room/stats.d.ts +66 -66
- package/dist/src/room/timers.d.ts +11 -12
- package/dist/src/room/timers.d.ts.map +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts +24 -24
- package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +43 -43
- package/dist/src/room/track/LocalTrackPublication.d.ts +37 -37
- package/dist/src/room/track/LocalVideoTrack.d.ts +53 -53
- package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteAudioTrack.d.ts +52 -52
- package/dist/src/room/track/RemoteAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteTrack.d.ts +14 -14
- package/dist/src/room/track/RemoteTrackPublication.d.ts +60 -60
- package/dist/src/room/track/RemoteVideoTrack.d.ts +52 -52
- package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts +124 -124
- package/dist/src/room/track/TrackPublication.d.ts +67 -67
- package/dist/src/room/track/create.d.ts +23 -23
- package/dist/src/room/track/create.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +255 -247
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/src/room/track/types.d.ts +22 -22
- package/dist/src/room/track/utils.d.ts +13 -13
- package/dist/src/room/types.d.ts +25 -25
- package/dist/src/room/utils.d.ts +86 -85
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/src/test/MockMediaStreamTrack.d.ts +25 -25
- package/dist/src/test/mocks.d.ts +10 -10
- package/dist/src/version.d.ts +2 -2
- package/dist/ts4.2/src/AsyncQueue.d.ts +23 -0
- package/dist/ts4.2/src/api/SignalClient.d.ts +2 -2
- package/dist/ts4.2/src/connectionHelper/ConnectionCheck.d.ts +2 -1
- package/dist/ts4.2/src/index.d.ts +8 -6
- package/dist/ts4.2/src/room/PCTransport.d.ts +2 -3
- package/dist/ts4.2/src/room/RTCEngine.d.ts +6 -1
- package/dist/ts4.2/src/room/defaults.d.ts +1 -1
- package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +4 -4
- package/dist/ts4.2/src/room/participant/RemoteParticipant.d.ts +2 -1
- package/dist/ts4.2/src/room/participant/publishUtils.d.ts +2 -1
- package/dist/ts4.2/src/room/timers.d.ts +4 -5
- package/dist/ts4.2/src/room/track/LocalAudioTrack.d.ts +1 -1
- package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +1 -1
- package/dist/ts4.2/src/room/track/RemoteAudioTrack.d.ts +1 -1
- package/dist/ts4.2/src/room/track/create.d.ts +1 -1
- package/dist/ts4.2/src/room/track/options.d.ts +10 -2
- package/dist/ts4.2/src/room/utils.d.ts +1 -0
- package/package.json +18 -31
- package/src/AsyncQueue.test.ts +99 -0
- package/src/AsyncQueue.ts +57 -0
- package/src/api/SignalClient.ts +14 -15
- package/src/connectionHelper/ConnectionCheck.ts +3 -2
- package/src/index.ts +13 -8
- package/src/room/PCTransport.ts +10 -6
- package/src/room/RTCEngine.ts +10 -3
- package/src/room/defaults.ts +6 -4
- package/src/room/participant/LocalParticipant.ts +10 -9
- package/src/room/participant/RemoteParticipant.ts +2 -1
- package/src/room/participant/publishUtils.ts +7 -5
- package/src/room/track/LocalAudioTrack.ts +2 -1
- package/src/room/track/LocalVideoTrack.ts +3 -2
- package/src/room/track/RemoteAudioTrack.ts +2 -1
- package/src/room/track/RemoteVideoTrack.ts +4 -8
- package/src/room/track/create.ts +2 -2
- package/src/room/track/options.ts +23 -7
- package/src/room/utils.ts +15 -2
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "livekit-client",
|
3
|
-
"version": "1.9.
|
3
|
+
"version": "1.9.4",
|
4
4
|
"description": "JavaScript/TypeScript client SDK for LiveKit",
|
5
5
|
"main": "./dist/livekit-client.umd.js",
|
6
6
|
"unpkg": "./dist/livekit-client.umd.js",
|
@@ -36,11 +36,11 @@
|
|
36
36
|
"deploy": "gh-pages -d example/dist",
|
37
37
|
"format": "prettier --write src example/sample.ts",
|
38
38
|
"format:check": "prettier --check src",
|
39
|
-
"release": "yarn build && changeset publish",
|
40
|
-
"downlevel-dts": "downlevel-dts ./dist/ ./dist/ts4.2 --to=4.2"
|
39
|
+
"release": "yarn build && yarn compat && changeset publish",
|
40
|
+
"downlevel-dts": "downlevel-dts ./dist/ ./dist/ts4.2 --to=4.2",
|
41
|
+
"compat": "eslint --no-eslintrc --config ./.eslintrc.dist.cjs ./dist/livekit-client.umd.js"
|
41
42
|
},
|
42
43
|
"dependencies": {
|
43
|
-
"async-await-queue": "^1.2.1",
|
44
44
|
"events": "^3.3.0",
|
45
45
|
"loglevel": "^1.8.0",
|
46
46
|
"protobufjs": "^7.0.0",
|
@@ -51,8 +51,8 @@
|
|
51
51
|
"webrtc-adapter": "^8.1.1"
|
52
52
|
},
|
53
53
|
"devDependencies": {
|
54
|
-
"@babel/core": "7.21.
|
55
|
-
"@babel/preset-env": "7.21.
|
54
|
+
"@babel/core": "7.21.8",
|
55
|
+
"@babel/preset-env": "7.21.5",
|
56
56
|
"@changesets/cli": "2.26.1",
|
57
57
|
"@livekit/changesets-changelog-github": "^0.0.4",
|
58
58
|
"@rollup/plugin-babel": "6.0.3",
|
@@ -61,44 +61,31 @@
|
|
61
61
|
"@rollup/plugin-node-resolve": "15.0.2",
|
62
62
|
"@rollup/plugin-terser": "^0.4.0",
|
63
63
|
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
|
64
|
-
"@types/
|
64
|
+
"@types/events": "^3.0.0",
|
65
|
+
"@types/jest": "29.5.1",
|
65
66
|
"@types/sdp-transform": "2.4.6",
|
66
67
|
"@types/ua-parser-js": "0.7.36",
|
67
|
-
"@
|
68
|
-
"@typescript-eslint/
|
69
|
-
"@typescript-eslint/parser": "5.58.0",
|
68
|
+
"@typescript-eslint/eslint-plugin": "5.59.2",
|
69
|
+
"@typescript-eslint/parser": "5.59.2",
|
70
70
|
"downlevel-dts": "^0.11.0",
|
71
|
-
"eslint": "8.
|
71
|
+
"eslint": "8.39.0",
|
72
72
|
"eslint-config-airbnb-typescript": "17.0.0",
|
73
73
|
"eslint-config-prettier": "8.8.0",
|
74
|
+
"eslint-plugin-ecmascript-compat": "^3.0.0",
|
74
75
|
"eslint-plugin-import": "2.27.5",
|
75
76
|
"gh-pages": "5.0.0",
|
76
77
|
"jest": "29.5.0",
|
77
78
|
"prettier": "^2.8.8",
|
78
|
-
"rollup": "3.
|
79
|
+
"rollup": "3.21.3",
|
79
80
|
"rollup-plugin-delete": "^2.0.0",
|
80
81
|
"rollup-plugin-filesize": "10.0.0",
|
81
82
|
"rollup-plugin-re": "1.0.7",
|
82
83
|
"rollup-plugin-typescript2": "0.34.1",
|
83
84
|
"ts-jest": "29.1.0",
|
84
|
-
"ts-proto": "1.
|
85
|
-
"typedoc": "0.24.
|
85
|
+
"ts-proto": "1.147.1",
|
86
|
+
"typedoc": "0.24.6",
|
86
87
|
"typedoc-plugin-no-inherit": "1.4.0",
|
87
|
-
"typescript": "
|
88
|
-
"vite": "4.
|
89
|
-
}
|
90
|
-
"browserslist": [
|
91
|
-
"safari >= 11",
|
92
|
-
"ios_saf >= 11",
|
93
|
-
"chrome >= 64",
|
94
|
-
"and_chr >= 64",
|
95
|
-
"android >= 64",
|
96
|
-
"firefox >= 53",
|
97
|
-
"and_ff >= 53",
|
98
|
-
"edge >= 79",
|
99
|
-
"Opera >= 52",
|
100
|
-
"Samsung >= 9.2",
|
101
|
-
"not IE 11",
|
102
|
-
"not dead"
|
103
|
-
]
|
88
|
+
"typescript": "5.0.4",
|
89
|
+
"vite": "4.3.4"
|
90
|
+
}
|
104
91
|
}
|
@@ -0,0 +1,99 @@
|
|
1
|
+
import { AsyncQueue } from './AsyncQueue';
|
2
|
+
import { sleep } from './room/utils';
|
3
|
+
|
4
|
+
describe('asyncQueue', () => {
|
5
|
+
it('runs multiple tasks in order', async () => {
|
6
|
+
const queue = new AsyncQueue();
|
7
|
+
const tasksExecuted: number[] = [];
|
8
|
+
|
9
|
+
for (let i = 0; i < 5; i++) {
|
10
|
+
queue.run(async () => {
|
11
|
+
await sleep(50);
|
12
|
+
tasksExecuted.push(i);
|
13
|
+
});
|
14
|
+
}
|
15
|
+
await queue.flush();
|
16
|
+
expect(tasksExecuted).toMatchObject([0, 1, 2, 3, 4]);
|
17
|
+
});
|
18
|
+
it('runs tasks sequentially and not in parallel', async () => {
|
19
|
+
const queue = new AsyncQueue();
|
20
|
+
const results: number[] = [];
|
21
|
+
for (let i = 0; i < 5; i++) {
|
22
|
+
queue.run(async () => {
|
23
|
+
results.push(i);
|
24
|
+
await sleep(10);
|
25
|
+
results.push(i);
|
26
|
+
});
|
27
|
+
}
|
28
|
+
await queue.flush();
|
29
|
+
expect(results).toMatchObject([0, 0, 1, 1, 2, 2, 3, 3, 4, 4]);
|
30
|
+
});
|
31
|
+
it('continues executing tasks if one task throws an error', async () => {
|
32
|
+
const queue = new AsyncQueue();
|
33
|
+
|
34
|
+
let task1threw = false;
|
35
|
+
let task2Executed = false;
|
36
|
+
|
37
|
+
queue
|
38
|
+
.run(async () => {
|
39
|
+
await sleep(100);
|
40
|
+
throw Error('task 1 throws');
|
41
|
+
})
|
42
|
+
.catch(() => {
|
43
|
+
task1threw = true;
|
44
|
+
});
|
45
|
+
|
46
|
+
await queue
|
47
|
+
.run(async () => {
|
48
|
+
task2Executed = true;
|
49
|
+
})
|
50
|
+
.catch(() => {
|
51
|
+
fail('task 2 should not have thrown');
|
52
|
+
});
|
53
|
+
|
54
|
+
expect(task1threw).toBeTruthy();
|
55
|
+
expect(task2Executed).toBeTruthy();
|
56
|
+
});
|
57
|
+
it('returns the result of the task', async () => {
|
58
|
+
const queue = new AsyncQueue();
|
59
|
+
|
60
|
+
const result = await queue.run(async () => {
|
61
|
+
await sleep(10);
|
62
|
+
return 'result';
|
63
|
+
});
|
64
|
+
|
65
|
+
expect(result).toBe('result');
|
66
|
+
});
|
67
|
+
it('returns only when the enqueued task and all previous tasks have completed', async () => {
|
68
|
+
const queue = new AsyncQueue();
|
69
|
+
const tasksExecuted: number[] = [];
|
70
|
+
for (let i = 0; i < 10; i += 1) {
|
71
|
+
queue.run(async () => {
|
72
|
+
await sleep(10);
|
73
|
+
tasksExecuted.push(i);
|
74
|
+
return i;
|
75
|
+
});
|
76
|
+
}
|
77
|
+
|
78
|
+
const result = await queue.run(async () => {
|
79
|
+
await sleep(10);
|
80
|
+
tasksExecuted.push(999);
|
81
|
+
return 'result';
|
82
|
+
});
|
83
|
+
|
84
|
+
expect(result).toBe('result');
|
85
|
+
expect(tasksExecuted).toMatchObject([...new Array(10).fill(0).map((_, idx) => idx), 999]);
|
86
|
+
});
|
87
|
+
it('can handle queue sizes of up to 10_000 tasks', async () => {
|
88
|
+
const queue = new AsyncQueue();
|
89
|
+
const tasksExecuted: number[] = [];
|
90
|
+
|
91
|
+
for (let i = 0; i < 10_000; i++) {
|
92
|
+
queue.run(async () => {
|
93
|
+
tasksExecuted.push(i);
|
94
|
+
});
|
95
|
+
}
|
96
|
+
await queue.flush();
|
97
|
+
expect(tasksExecuted).toMatchObject(new Array(10_000).fill(0).map((_, idx) => idx));
|
98
|
+
});
|
99
|
+
});
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import { Mutex } from './room/utils';
|
2
|
+
|
3
|
+
type QueueTask<T> = () => PromiseLike<T>;
|
4
|
+
|
5
|
+
enum QueueTaskStatus {
|
6
|
+
'WAITING',
|
7
|
+
'RUNNING',
|
8
|
+
'COMPLETED',
|
9
|
+
}
|
10
|
+
|
11
|
+
type QueueTaskInfo = {
|
12
|
+
id: number;
|
13
|
+
enqueuedAt: number;
|
14
|
+
executedAt?: number;
|
15
|
+
status: QueueTaskStatus;
|
16
|
+
};
|
17
|
+
|
18
|
+
export class AsyncQueue {
|
19
|
+
private pendingTasks: Map<number, QueueTaskInfo>;
|
20
|
+
|
21
|
+
private taskMutex: Mutex;
|
22
|
+
|
23
|
+
private nextTaskIndex: number;
|
24
|
+
|
25
|
+
constructor() {
|
26
|
+
this.pendingTasks = new Map();
|
27
|
+
this.taskMutex = new Mutex();
|
28
|
+
this.nextTaskIndex = 0;
|
29
|
+
}
|
30
|
+
|
31
|
+
async run<T>(task: QueueTask<T>) {
|
32
|
+
const taskInfo: QueueTaskInfo = {
|
33
|
+
id: this.nextTaskIndex++,
|
34
|
+
enqueuedAt: Date.now(),
|
35
|
+
status: QueueTaskStatus.WAITING,
|
36
|
+
};
|
37
|
+
this.pendingTasks.set(taskInfo.id, taskInfo);
|
38
|
+
const unlock = await this.taskMutex.lock();
|
39
|
+
try {
|
40
|
+
taskInfo.executedAt = Date.now();
|
41
|
+
taskInfo.status = QueueTaskStatus.RUNNING;
|
42
|
+
return await task();
|
43
|
+
} finally {
|
44
|
+
taskInfo.status = QueueTaskStatus.COMPLETED;
|
45
|
+
this.pendingTasks.delete(taskInfo.id);
|
46
|
+
unlock();
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
async flush() {
|
51
|
+
return this.run(async () => {});
|
52
|
+
}
|
53
|
+
|
54
|
+
snapshot() {
|
55
|
+
return Array.from(this.pendingTasks.values());
|
56
|
+
}
|
57
|
+
}
|
package/src/api/SignalClient.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import Queue from 'async-await-queue';
|
2
1
|
import 'webrtc-adapter';
|
2
|
+
import { AsyncQueue } from '../AsyncQueue';
|
3
3
|
import log from '../logger';
|
4
4
|
import {
|
5
5
|
ClientInfo,
|
@@ -76,7 +76,7 @@ const passThroughQueueSignals: Array<SignalKind> = [
|
|
76
76
|
];
|
77
77
|
|
78
78
|
function canPassThroughQueue(req: SignalMessage): boolean {
|
79
|
-
const canPass = passThroughQueueSignals.
|
79
|
+
const canPass = passThroughQueueSignals.indexOf(req!.$case) >= 0;
|
80
80
|
log.trace('request allowed to bypass queue:', { canPass, req });
|
81
81
|
return canPass;
|
82
82
|
}
|
@@ -87,7 +87,7 @@ export class SignalClient {
|
|
87
87
|
|
88
88
|
isReconnecting: boolean;
|
89
89
|
|
90
|
-
requestQueue:
|
90
|
+
requestQueue: AsyncQueue;
|
91
91
|
|
92
92
|
queuedRequests: Array<() => Promise<void>>;
|
93
93
|
|
@@ -154,7 +154,7 @@ export class SignalClient {
|
|
154
154
|
this.isConnected = false;
|
155
155
|
this.isReconnecting = false;
|
156
156
|
this.useJSON = useJSON;
|
157
|
-
this.requestQueue = new
|
157
|
+
this.requestQueue = new AsyncQueue();
|
158
158
|
this.queuedRequests = [];
|
159
159
|
this.closingLock = new Mutex();
|
160
160
|
}
|
@@ -321,6 +321,7 @@ export class SignalClient {
|
|
321
321
|
};
|
322
322
|
|
323
323
|
this.ws.onclose = (ev: CloseEvent) => {
|
324
|
+
log.warn(`websocket closed`, { ev });
|
324
325
|
this.handleOnClose(ev.reason);
|
325
326
|
};
|
326
327
|
});
|
@@ -344,12 +345,14 @@ export class SignalClient {
|
|
344
345
|
}
|
345
346
|
});
|
346
347
|
|
347
|
-
this.ws.
|
348
|
-
|
349
|
-
|
348
|
+
if (this.ws.readyState < this.ws.CLOSING) {
|
349
|
+
this.ws.close();
|
350
|
+
// 250ms grace period for ws to close gracefully
|
351
|
+
await Promise.race([closePromise, sleep(250)]);
|
352
|
+
}
|
353
|
+
this.ws = undefined;
|
354
|
+
this.clearPingInterval();
|
350
355
|
}
|
351
|
-
this.ws = undefined;
|
352
|
-
this.clearPingInterval();
|
353
356
|
} finally {
|
354
357
|
unlock();
|
355
358
|
}
|
@@ -611,17 +614,13 @@ export class SignalClient {
|
|
611
614
|
this.isReconnecting = false;
|
612
615
|
}
|
613
616
|
|
614
|
-
private handleOnClose(reason: string) {
|
617
|
+
private async handleOnClose(reason: string) {
|
615
618
|
if (!this.isConnected) return;
|
616
|
-
this.
|
617
|
-
this.clearPingTimeout();
|
618
|
-
|
619
|
+
await this.close();
|
619
620
|
log.debug(`websocket connection closed: ${reason}`);
|
620
|
-
this.isConnected = false;
|
621
621
|
if (this.onClose) {
|
622
622
|
this.onClose(reason);
|
623
623
|
}
|
624
|
-
this.ws = undefined;
|
625
624
|
}
|
626
625
|
|
627
626
|
private handleWSError(ev: Event) {
|
@@ -1,6 +1,7 @@
|
|
1
|
-
import EventEmitter from 'events';
|
1
|
+
import { EventEmitter } from 'events';
|
2
2
|
import type TypedEmitter from 'typed-emitter';
|
3
|
-
import {
|
3
|
+
import { CheckStatus, Checker } from './checks/Checker';
|
4
|
+
import type { CheckInfo, InstantiableCheck } from './checks/Checker';
|
4
5
|
import { PublishAudioCheck } from './checks/publishAudio';
|
5
6
|
import { PublishVideoCheck } from './checks/publishVideo';
|
6
7
|
import { ReconnectCheck } from './checks/reconnect';
|
package/src/index.ts
CHANGED
@@ -14,11 +14,12 @@ import LocalVideoTrack from './room/track/LocalVideoTrack';
|
|
14
14
|
import RemoteAudioTrack from './room/track/RemoteAudioTrack';
|
15
15
|
import RemoteTrack from './room/track/RemoteTrack';
|
16
16
|
import RemoteTrackPublication from './room/track/RemoteTrackPublication';
|
17
|
-
import
|
17
|
+
import type { ElementInfo } from './room/track/RemoteVideoTrack';
|
18
|
+
import RemoteVideoTrack from './room/track/RemoteVideoTrack';
|
18
19
|
import { TrackPublication } from './room/track/TrackPublication';
|
19
20
|
import type { LiveKitReactNativeInfo } from './room/types';
|
21
|
+
import type { AudioAnalyserOptions } from './room/utils';
|
20
22
|
import {
|
21
|
-
type AudioAnalyserOptions,
|
22
23
|
createAudioAnalyser,
|
23
24
|
getEmptyAudioStreamTrack,
|
24
25
|
getEmptyVideoStreamTrack,
|
@@ -26,18 +27,19 @@ import {
|
|
26
27
|
supportsAV1,
|
27
28
|
supportsAdaptiveStream,
|
28
29
|
supportsDynacast,
|
30
|
+
supportsVP9,
|
29
31
|
} from './room/utils';
|
30
32
|
|
33
|
+
export * from './connectionHelper/ConnectionCheck';
|
31
34
|
export * from './options';
|
32
35
|
export * from './room/errors';
|
33
36
|
export * from './room/events';
|
34
|
-
export
|
37
|
+
export * from './room/track/Track';
|
35
38
|
export * from './room/track/create';
|
36
39
|
export * from './room/track/options';
|
37
|
-
export * from './room/track/Track';
|
38
40
|
export * from './room/track/types';
|
41
|
+
export type { DataPublishOptions, SimulationScenario } from './room/types';
|
39
42
|
export * from './version';
|
40
|
-
export * from './connectionHelper/ConnectionCheck';
|
41
43
|
export {
|
42
44
|
setLogLevel,
|
43
45
|
setLogExtension,
|
@@ -47,8 +49,8 @@ export {
|
|
47
49
|
supportsAdaptiveStream,
|
48
50
|
supportsDynacast,
|
49
51
|
supportsAV1,
|
52
|
+
supportsVP9,
|
50
53
|
createAudioAnalyser,
|
51
|
-
AudioAnalyserOptions,
|
52
54
|
LogLevel,
|
53
55
|
Room,
|
54
56
|
ConnectionState,
|
@@ -66,12 +68,15 @@ export {
|
|
66
68
|
RemoteAudioTrack,
|
67
69
|
RemoteVideoTrack,
|
68
70
|
RemoteTrackPublication,
|
69
|
-
ParticipantTrackPermission,
|
70
71
|
TrackPublication,
|
71
72
|
VideoQuality,
|
72
73
|
ConnectionQuality,
|
73
|
-
ElementInfo,
|
74
74
|
DefaultReconnectPolicy,
|
75
75
|
CriticalTimers,
|
76
|
+
};
|
77
|
+
export type {
|
78
|
+
ElementInfo,
|
79
|
+
ParticipantTrackPermission,
|
80
|
+
AudioAnalyserOptions,
|
76
81
|
LiveKitReactNativeInfo,
|
77
82
|
};
|
package/src/room/PCTransport.ts
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
import EventEmitter from 'events';
|
2
|
-
import {
|
1
|
+
import { EventEmitter } from 'events';
|
2
|
+
import { parse, write } from 'sdp-transform';
|
3
|
+
import type { MediaDescription } from 'sdp-transform';
|
3
4
|
import { debounce } from 'ts-debounce';
|
4
5
|
import log from '../logger';
|
5
6
|
import { NegotiationError } from './errors';
|
6
|
-
import { ddExtensionURI, isSVCCodec } from './utils';
|
7
|
+
import { ddExtensionURI, isChromiumBased, isSVCCodec } from './utils';
|
7
8
|
|
8
9
|
/** @internal */
|
9
10
|
interface TrackBitrateInfo {
|
@@ -35,9 +36,12 @@ export default class PCTransport extends EventEmitter {
|
|
35
36
|
|
36
37
|
onOffer?: (offer: RTCSessionDescriptionInit) => void;
|
37
38
|
|
38
|
-
constructor(config?: RTCConfiguration) {
|
39
|
+
constructor(config?: RTCConfiguration, mediaConstraints: Record<string, unknown> = {}) {
|
39
40
|
super();
|
40
|
-
this.pc =
|
41
|
+
this.pc = isChromiumBased()
|
42
|
+
? // @ts-expect-error chrome allows additional media constraints to be passed into the RTCPeerConnection constructor
|
43
|
+
new RTCPeerConnection(config, mediaConstraints)
|
44
|
+
: new RTCPeerConnection(config);
|
41
45
|
}
|
42
46
|
|
43
47
|
get isICEConnected(): boolean {
|
@@ -289,7 +293,7 @@ function ensureVideoDDExtensionForSVC(
|
|
289
293
|
payloads?: string | undefined;
|
290
294
|
} & MediaDescription,
|
291
295
|
) {
|
292
|
-
const codec = media.rtp
|
296
|
+
const codec = media.rtp[0]?.codec?.toLowerCase();
|
293
297
|
if (!isSVCCodec(codec)) {
|
294
298
|
return;
|
295
299
|
}
|
package/src/room/RTCEngine.ts
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import { EventEmitter } from 'events';
|
2
2
|
import type TypedEventEmitter from 'typed-emitter';
|
3
|
-
import { SignalClient
|
3
|
+
import { SignalClient } from '../api/SignalClient';
|
4
|
+
import type { SignalOptions } from '../api/SignalClient';
|
4
5
|
import log from '../logger';
|
5
6
|
import type { InternalRoomOptions } from '../options';
|
6
7
|
import {
|
@@ -77,6 +78,11 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
77
78
|
|
78
79
|
fullReconnectOnNext: boolean = false;
|
79
80
|
|
81
|
+
/**
|
82
|
+
* @internal
|
83
|
+
*/
|
84
|
+
latestJoinResponse?: JoinResponse;
|
85
|
+
|
80
86
|
get isClosed() {
|
81
87
|
return this._isClosed;
|
82
88
|
}
|
@@ -171,6 +177,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
171
177
|
this.joinAttempts += 1;
|
172
178
|
const joinResponse = await this.client.join(url, token, opts, abortSignal);
|
173
179
|
this._isClosed = false;
|
180
|
+
this.latestJoinResponse = joinResponse;
|
174
181
|
|
175
182
|
this.subscriberPrimary = joinResponse.subscriberPrimary;
|
176
183
|
if (!this.publisher) {
|
@@ -307,8 +314,8 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
|
|
307
314
|
this.participantSid = joinResponse.participant?.sid;
|
308
315
|
|
309
316
|
const rtcConfig = this.makeRTCConfiguration(joinResponse);
|
310
|
-
|
311
|
-
this.publisher = new PCTransport(rtcConfig);
|
317
|
+
const googConstraints = { optional: [{ googDscp: true }] };
|
318
|
+
this.publisher = new PCTransport(rtcConfig, googConstraints);
|
312
319
|
this.subscriber = new PCTransport(rtcConfig);
|
313
320
|
|
314
321
|
this.emit(EngineEvent.TransportsCreated, this.publisher, this.subscriber);
|
package/src/room/defaults.ts
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
import type { InternalRoomConnectOptions, InternalRoomOptions } from '../options';
|
2
2
|
import DefaultReconnectPolicy from './DefaultReconnectPolicy';
|
3
|
-
import {
|
3
|
+
import { AudioPresets, ScreenSharePresets, VideoPresets } from './track/options';
|
4
|
+
import type {
|
4
5
|
AudioCaptureOptions,
|
5
|
-
AudioPresets,
|
6
|
-
ScreenSharePresets,
|
7
6
|
TrackPublishDefaults,
|
8
7
|
VideoCaptureOptions,
|
9
|
-
VideoPresets,
|
10
8
|
} from './track/options';
|
11
9
|
|
12
10
|
export const publishDefaults: TrackPublishDefaults = {
|
11
|
+
/**
|
12
|
+
* @deprecated
|
13
|
+
*/
|
13
14
|
audioBitrate: AudioPresets.music.maxBitrate,
|
15
|
+
audioPreset: AudioPresets.music,
|
14
16
|
dtx: true,
|
15
17
|
red: true,
|
16
18
|
forceStereo: false,
|
@@ -18,22 +18,21 @@ import LocalTrack from '../track/LocalTrack';
|
|
18
18
|
import LocalTrackPublication from '../track/LocalTrackPublication';
|
19
19
|
import LocalVideoTrack, { videoLayersFromEncodings } from '../track/LocalVideoTrack';
|
20
20
|
import { Track } from '../track/Track';
|
21
|
-
import {
|
21
|
+
import { ScreenSharePresets, isBackupCodec, isCodecEqual } from '../track/options';
|
22
|
+
import type {
|
22
23
|
AudioCaptureOptions,
|
23
24
|
BackupVideoCodec,
|
24
25
|
CreateLocalTracksOptions,
|
25
26
|
ScreenShareCaptureOptions,
|
26
|
-
ScreenSharePresets,
|
27
27
|
TrackPublishOptions,
|
28
28
|
VideoCaptureOptions,
|
29
|
-
isBackupCodec,
|
30
|
-
isCodecEqual,
|
31
29
|
} from '../track/options';
|
32
30
|
import { constraintsForOptions, mergeDefaultOptions } from '../track/utils';
|
33
31
|
import type { DataPublishOptions } from '../types';
|
34
32
|
import { Future, isFireFox, isSVCCodec, isSafari, isWeb, supportsAV1, supportsVP9 } from '../utils';
|
35
33
|
import Participant from './Participant';
|
36
|
-
import {
|
34
|
+
import { trackPermissionToProto } from './ParticipantTrackPermission';
|
35
|
+
import type { ParticipantTrackPermission } from './ParticipantTrackPermission';
|
37
36
|
import RemoteParticipant from './RemoteParticipant';
|
38
37
|
import {
|
39
38
|
computeTrackBackupEncodings,
|
@@ -151,7 +150,7 @@ export default class LocalParticipant extends Participant {
|
|
151
150
|
|
152
151
|
/**
|
153
152
|
* Sets and updates the metadata of the local participant.
|
154
|
-
* Note: this requires `
|
153
|
+
* Note: this requires `canUpdateOwnMetadata` permission encoded in the token.
|
155
154
|
* @param metadata
|
156
155
|
*/
|
157
156
|
setMetadata(metadata: string): void {
|
@@ -161,7 +160,7 @@ export default class LocalParticipant extends Participant {
|
|
161
160
|
|
162
161
|
/**
|
163
162
|
* Sets and updates the name of the local participant.
|
164
|
-
* Note: this requires `
|
163
|
+
* Note: this requires `canUpdateOwnMetadata` permission encoded in the token.
|
165
164
|
* @param metadata
|
166
165
|
*/
|
167
166
|
setName(name: string): void {
|
@@ -651,10 +650,12 @@ export default class LocalParticipant extends Participant {
|
|
651
650
|
opts,
|
652
651
|
);
|
653
652
|
req.layers = videoLayersFromEncodings(req.width, req.height, simEncodings ?? encodings);
|
654
|
-
} else if (track.kind === Track.Kind.Audio
|
653
|
+
} else if (track.kind === Track.Kind.Audio) {
|
655
654
|
encodings = [
|
656
655
|
{
|
657
|
-
maxBitrate: opts.audioBitrate,
|
656
|
+
maxBitrate: opts.audioPreset?.maxBitrate ?? opts.audioBitrate,
|
657
|
+
priority: opts.audioPreset?.priority ?? 'high',
|
658
|
+
networkPriority: opts.audioPreset?.priority ?? 'high',
|
658
659
|
},
|
659
660
|
];
|
660
661
|
}
|
@@ -11,7 +11,8 @@ import { Track } from '../track/Track';
|
|
11
11
|
import type { TrackPublication } from '../track/TrackPublication';
|
12
12
|
import type { AudioOutputOptions } from '../track/options';
|
13
13
|
import type { AdaptiveStreamSettings } from '../track/types';
|
14
|
-
import Participant
|
14
|
+
import Participant from './Participant';
|
15
|
+
import type { ParticipantEventCallbacks } from './Participant';
|
15
16
|
|
16
17
|
export default class RemoteParticipant extends Participant {
|
17
18
|
audioTracks: Map<string, RemoteTrackPublication>;
|
@@ -3,15 +3,12 @@ import { TrackInvalidError } from '../errors';
|
|
3
3
|
import LocalAudioTrack from '../track/LocalAudioTrack';
|
4
4
|
import LocalVideoTrack from '../track/LocalVideoTrack';
|
5
5
|
import { Track } from '../track/Track';
|
6
|
-
import {
|
6
|
+
import { ScreenSharePresets, VideoPreset, VideoPresets, VideoPresets43 } from '../track/options';
|
7
|
+
import type {
|
7
8
|
BackupVideoCodec,
|
8
|
-
ScreenSharePresets,
|
9
9
|
TrackPublishOptions,
|
10
10
|
VideoCodec,
|
11
11
|
VideoEncoding,
|
12
|
-
VideoPreset,
|
13
|
-
VideoPresets,
|
14
|
-
VideoPresets43,
|
15
12
|
} from '../track/options';
|
16
13
|
import { isSVCCodec } from '../utils';
|
17
14
|
|
@@ -61,6 +58,7 @@ export const computeDefaultScreenShareSimulcastPresets = (fromPreset: VideoPrese
|
|
61
58
|
),
|
62
59
|
),
|
63
60
|
t.fps,
|
61
|
+
fromPreset.encoding.priority,
|
64
62
|
),
|
65
63
|
);
|
66
64
|
};
|
@@ -317,6 +315,10 @@ function encodingsFromPresets(
|
|
317
315
|
if (preset.encoding.maxFramerate) {
|
318
316
|
encoding.maxFramerate = preset.encoding.maxFramerate;
|
319
317
|
}
|
318
|
+
if (preset.encoding.priority) {
|
319
|
+
encoding.priority = preset.encoding.priority;
|
320
|
+
encoding.networkPriority = preset.encoding.priority;
|
321
|
+
}
|
320
322
|
encodings.push(encoding);
|
321
323
|
});
|
322
324
|
return encodings;
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import log from '../../logger';
|
2
2
|
import { TrackEvent } from '../events';
|
3
|
-
import {
|
3
|
+
import { computeBitrate, monitorFrequency } from '../stats';
|
4
|
+
import type { AudioSenderStats } from '../stats';
|
4
5
|
import { isWeb } from '../utils';
|
5
6
|
import LocalTrack from './LocalTrack';
|
6
7
|
import { Track } from './Track';
|
@@ -2,7 +2,8 @@ import type { SignalClient } from '../../api/SignalClient';
|
|
2
2
|
import log from '../../logger';
|
3
3
|
import { VideoLayer, VideoQuality } from '../../proto/livekit_models';
|
4
4
|
import type { SubscribedCodec, SubscribedQuality } from '../../proto/livekit_rtc';
|
5
|
-
import {
|
5
|
+
import { computeBitrate, monitorFrequency } from '../stats';
|
6
|
+
import type { VideoSenderStats } from '../stats';
|
6
7
|
import { Mutex, isFireFox, isMobile, isWeb } from '../utils';
|
7
8
|
import LocalTrack from './LocalTrack';
|
8
9
|
import { Track } from './Track';
|
@@ -153,7 +154,7 @@ export default class LocalVideoTrack extends LocalTrack {
|
|
153
154
|
qualityLimitationResolutionChanges: v.qualityLimitationResolutionChanges,
|
154
155
|
};
|
155
156
|
|
156
|
-
//
|
157
|
+
// locate the appropriate remote-inbound-rtp item
|
157
158
|
const r = stats.get(v.remoteId);
|
158
159
|
if (r) {
|
159
160
|
vs.jitter = r.jitter;
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import log from '../../logger';
|
2
2
|
import { TrackEvent } from '../events';
|
3
|
-
import {
|
3
|
+
import { computeBitrate } from '../stats';
|
4
|
+
import type { AudioReceiverStats } from '../stats';
|
4
5
|
import { supportsSetSinkId } from '../utils';
|
5
6
|
import RemoteTrack from './RemoteTrack';
|
6
7
|
import { Track } from './Track';
|
@@ -1,15 +1,11 @@
|
|
1
1
|
import { debounce } from 'ts-debounce';
|
2
2
|
import log from '../../logger';
|
3
3
|
import { TrackEvent } from '../events';
|
4
|
-
import {
|
4
|
+
import { computeBitrate } from '../stats';
|
5
|
+
import type { VideoReceiverStats } from '../stats';
|
5
6
|
import CriticalTimers from '../timers';
|
6
|
-
import {
|
7
|
-
|
8
|
-
getDevicePixelRatio,
|
9
|
-
getIntersectionObserver,
|
10
|
-
getResizeObserver,
|
11
|
-
isWeb,
|
12
|
-
} from '../utils';
|
7
|
+
import { getDevicePixelRatio, getIntersectionObserver, getResizeObserver, isWeb } from '../utils';
|
8
|
+
import type { ObservableMediaElement } from '../utils';
|
13
9
|
import RemoteTrack from './RemoteTrack';
|
14
10
|
import { Track, attachToElement, detachTrack } from './Track';
|
15
11
|
import type { AdaptiveStreamSettings } from './types';
|