livekit-client 1.14.1 → 1.14.3
Sign up to get free protection for your applications and to get access to all the features.
- 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 +25 -44
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +555 -306
- 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/e2ee/E2eeManager.d.ts.map +1 -1
- package/dist/src/e2ee/utils.d.ts +0 -1
- package/dist/src/e2ee/utils.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/ParticipantKeyHandler.d.ts.map +1 -1
- package/dist/src/proto/livekit_models_pb.d.ts +87 -11
- package/dist/src/proto/livekit_models_pb.d.ts.map +1 -1
- package/dist/src/proto/livekit_rtc_pb.d.ts +0 -4
- package/dist/src/proto/livekit_rtc_pb.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +20 -1
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +1 -1
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +1 -1
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/defaults.d.ts +1 -0
- package/dist/src/room/defaults.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +3 -1
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/Participant.d.ts +1 -0
- package/dist/src/room/participant/Participant.d.ts.map +1 -1
- package/dist/src/room/timers.d.ts +1 -1
- package/dist/src/room/timers.d.ts.map +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +3 -3
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalVideoTrack.d.ts +2 -1
- package/dist/src/room/track/LocalVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +0 -1
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/src/room/track/utils.d.ts +2 -1
- package/dist/src/room/track/utils.d.ts.map +1 -1
- package/dist/src/utils/cloneDeep.d.ts +2 -0
- package/dist/src/utils/cloneDeep.d.ts.map +1 -0
- package/dist/ts4.2/src/e2ee/utils.d.ts +0 -1
- package/dist/ts4.2/src/proto/livekit_models_pb.d.ts +87 -11
- package/dist/ts4.2/src/proto/livekit_rtc_pb.d.ts +0 -4
- package/dist/ts4.2/src/room/PCTransport.d.ts +20 -1
- package/dist/ts4.2/src/room/RTCEngine.d.ts +1 -1
- package/dist/ts4.2/src/room/Room.d.ts +1 -1
- package/dist/ts4.2/src/room/defaults.d.ts +1 -0
- package/dist/ts4.2/src/room/events.d.ts +3 -1
- package/dist/ts4.2/src/room/participant/Participant.d.ts +1 -0
- package/dist/ts4.2/src/room/timers.d.ts +1 -1
- package/dist/ts4.2/src/room/track/LocalAudioTrack.d.ts +1 -1
- package/dist/ts4.2/src/room/track/LocalTrack.d.ts +3 -3
- package/dist/ts4.2/src/room/track/LocalVideoTrack.d.ts +2 -1
- package/dist/ts4.2/src/room/track/options.d.ts +0 -1
- package/dist/ts4.2/src/room/track/utils.d.ts +1 -0
- package/dist/ts4.2/src/utils/cloneDeep.d.ts +2 -0
- package/package.json +15 -15
- package/src/connectionHelper/checks/webrtc.ts +1 -1
- package/src/e2ee/E2eeManager.ts +2 -1
- package/src/e2ee/utils.ts +0 -10
- package/src/e2ee/worker/FrameCryptor.ts +13 -14
- package/src/e2ee/worker/ParticipantKeyHandler.ts +4 -5
- package/src/e2ee/worker/e2ee.worker.ts +3 -1
- package/src/proto/livekit_models_pb.ts +140 -15
- package/src/proto/livekit_rtc_pb.ts +1 -7
- package/src/room/PCTransport.ts +122 -5
- package/src/room/RTCEngine.ts +56 -92
- package/src/room/Room.ts +14 -11
- package/src/room/defaults.ts +4 -2
- package/src/room/events.ts +5 -1
- package/src/room/participant/LocalParticipant.ts +47 -68
- package/src/room/participant/Participant.ts +1 -0
- package/src/room/track/LocalAudioTrack.ts +1 -1
- package/src/room/track/LocalTrack.ts +8 -5
- package/src/room/track/LocalVideoTrack.ts +2 -1
- package/src/room/track/Track.ts +6 -1
- package/src/room/track/options.ts +0 -7
- package/src/room/track/utils.ts +17 -8
- package/src/utils/cloneDeep.test.ts +54 -0
- package/src/utils/cloneDeep.ts +11 -0
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "livekit-client",
|
3
|
-
"version": "1.14.
|
3
|
+
"version": "1.14.3",
|
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",
|
@@ -61,42 +61,42 @@
|
|
61
61
|
"webrtc-adapter": "^8.1.1"
|
62
62
|
},
|
63
63
|
"devDependencies": {
|
64
|
-
"@babel/core": "7.
|
65
|
-
"@babel/preset-env": "7.
|
64
|
+
"@babel/core": "7.23.2",
|
65
|
+
"@babel/preset-env": "7.23.2",
|
66
66
|
"@bufbuild/protoc-gen-es": "^1.3.0",
|
67
67
|
"@changesets/cli": "2.26.2",
|
68
68
|
"@livekit/changesets-changelog-github": "^0.0.4",
|
69
|
-
"@rollup/plugin-babel": "6.0.
|
70
|
-
"@rollup/plugin-commonjs": "25.0.
|
71
|
-
"@rollup/plugin-json": "6.0.
|
72
|
-
"@rollup/plugin-node-resolve": "15.2.
|
69
|
+
"@rollup/plugin-babel": "6.0.4",
|
70
|
+
"@rollup/plugin-commonjs": "25.0.7",
|
71
|
+
"@rollup/plugin-json": "6.0.1",
|
72
|
+
"@rollup/plugin-node-resolve": "15.2.3",
|
73
73
|
"@rollup/plugin-terser": "^0.4.0",
|
74
74
|
"@size-limit/file": "^8.2.4",
|
75
75
|
"@size-limit/webpack": "^8.2.4",
|
76
76
|
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
|
77
77
|
"@types/events": "^3.0.0",
|
78
|
-
"@types/sdp-transform": "2.4.
|
79
|
-
"@types/ua-parser-js": "0.7.
|
78
|
+
"@types/sdp-transform": "2.4.8",
|
79
|
+
"@types/ua-parser-js": "0.7.38",
|
80
80
|
"@typescript-eslint/eslint-plugin": "5.62.0",
|
81
81
|
"@typescript-eslint/parser": "5.62.0",
|
82
82
|
"downlevel-dts": "^0.11.0",
|
83
|
-
"eslint": "8.
|
83
|
+
"eslint": "8.52.0",
|
84
84
|
"eslint-config-airbnb-typescript": "17.1.0",
|
85
85
|
"eslint-config-prettier": "9.0.0",
|
86
86
|
"eslint-plugin-ecmascript-compat": "^3.0.0",
|
87
|
-
"eslint-plugin-import": "2.
|
87
|
+
"eslint-plugin-import": "2.29.0",
|
88
88
|
"gh-pages": "6.0.0",
|
89
89
|
"jsdom": "^22.1.0",
|
90
90
|
"prettier": "^2.8.8",
|
91
|
-
"rollup": "3.
|
91
|
+
"rollup": "3.29.4",
|
92
92
|
"rollup-plugin-delete": "^2.0.0",
|
93
93
|
"rollup-plugin-re": "1.0.7",
|
94
|
-
"rollup-plugin-typescript2": "0.
|
94
|
+
"rollup-plugin-typescript2": "0.36.0",
|
95
95
|
"size-limit": "^8.2.4",
|
96
|
-
"typedoc": "0.25.
|
96
|
+
"typedoc": "0.25.3",
|
97
97
|
"typedoc-plugin-no-inherit": "1.4.0",
|
98
98
|
"typescript": "5.2.2",
|
99
|
-
"vite": "4.
|
99
|
+
"vite": "4.5.0",
|
100
100
|
"vitest": "^0.34.0"
|
101
101
|
}
|
102
102
|
}
|
@@ -39,7 +39,7 @@ export class WebRTCCheck extends Checker {
|
|
39
39
|
};
|
40
40
|
|
41
41
|
if (this.room.engine.subscriber) {
|
42
|
-
this.room.engine.subscriber.
|
42
|
+
this.room.engine.subscriber.onIceCandidateError = (ev) => {
|
43
43
|
if (ev instanceof RTCPeerConnectionIceErrorEvent) {
|
44
44
|
this.appendWarning(
|
45
45
|
`error with ICE candidate: ${ev.errorCode} ${ev.errorText} ${ev.url}`,
|
package/src/e2ee/E2eeManager.ts
CHANGED
@@ -11,6 +11,7 @@ import LocalTrack from '../room/track/LocalTrack';
|
|
11
11
|
import type RemoteTrack from '../room/track/RemoteTrack';
|
12
12
|
import type { Track } from '../room/track/Track';
|
13
13
|
import type { VideoCodec } from '../room/track/options';
|
14
|
+
import { mimeTypeToVideoCodecString } from '../room/track/utils';
|
14
15
|
import type { BaseKeyProvider } from './KeyProvider';
|
15
16
|
import { E2EE_FLAG } from './constants';
|
16
17
|
import { type E2EEManagerCallbacks, EncryptionEvent, KeyProviderEvent } from './events';
|
@@ -28,7 +29,7 @@ import type {
|
|
28
29
|
SifTrailerMessage,
|
29
30
|
UpdateCodecMessage,
|
30
31
|
} from './types';
|
31
|
-
import { isE2EESupported, isScriptTransformSupported
|
32
|
+
import { isE2EESupported, isScriptTransformSupported } from './utils';
|
32
33
|
|
33
34
|
/**
|
34
35
|
* @experimental
|
package/src/e2ee/utils.ts
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
import { videoCodecs } from '../room/track/options';
|
2
|
-
import type { VideoCodec } from '../room/track/options';
|
3
1
|
import { ENCRYPTION_ALGORITHM } from './constants';
|
4
2
|
|
5
3
|
export function isE2EESupported() {
|
@@ -116,14 +114,6 @@ export function createE2EEKey(): Uint8Array {
|
|
116
114
|
return window.crypto.getRandomValues(new Uint8Array(32));
|
117
115
|
}
|
118
116
|
|
119
|
-
export function mimeTypeToVideoCodecString(mimeType: string) {
|
120
|
-
const codec = mimeType.split('/')[1].toLowerCase() as VideoCodec;
|
121
|
-
if (!videoCodecs.includes(codec)) {
|
122
|
-
throw Error(`Video codec not supported: ${codec}`);
|
123
|
-
}
|
124
|
-
return codec;
|
125
|
-
}
|
126
|
-
|
127
117
|
/**
|
128
118
|
* Ratchets a key. See
|
129
119
|
* https://tools.ietf.org/html/draft-omara-sframe-00#section-4.3.5.1
|
@@ -326,11 +326,11 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
326
326
|
}
|
327
327
|
} else if (!this.keys.getKeySet(keyIndex) && this.keys.hasValidKey) {
|
328
328
|
// emit an error in case the key index is out of bounds but the key handler thinks we still have a valid key
|
329
|
-
workerLogger.warn(
|
329
|
+
workerLogger.warn(`skipping decryption due to missing key at index ${keyIndex}`);
|
330
330
|
this.emit(
|
331
331
|
CryptorEvent.Error,
|
332
332
|
new CryptorError(
|
333
|
-
`missing key at index for participant ${this.participantIdentity}`,
|
333
|
+
`missing key at index ${keyIndex} for participant ${this.participantIdentity}`,
|
334
334
|
CryptorErrorReason.MissingKey,
|
335
335
|
),
|
336
336
|
);
|
@@ -418,7 +418,7 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
418
418
|
);
|
419
419
|
|
420
420
|
let ratchetedKeySet: KeySet | undefined;
|
421
|
-
if (keySet === this.keys.getKeySet(keyIndex)) {
|
421
|
+
if ((initialMaterial ?? keySet) === this.keys.getKeySet(keyIndex)) {
|
422
422
|
// only ratchet if the currently set key is still the same as the one used to decrypt this frame
|
423
423
|
// if not, it might be that a different frame has already ratcheted and we try with that one first
|
424
424
|
const newMaterial = await this.keys.ratchetKey(keyIndex, false);
|
@@ -431,22 +431,21 @@ export class FrameCryptor extends BaseFrameCryptor {
|
|
431
431
|
encryptionKey: ratchetedKeySet?.encryptionKey,
|
432
432
|
});
|
433
433
|
if (frame && ratchetedKeySet) {
|
434
|
-
|
435
|
-
//
|
436
|
-
this.keys.
|
434
|
+
// before updating the keys, make sure that the keySet used for this frame is still the same as the currently set key
|
435
|
+
// if it's not, a new key might have been set already, which we don't want to override
|
436
|
+
if ((initialMaterial ?? keySet) === this.keys.getKeySet(keyIndex)) {
|
437
|
+
this.keys.setKeySet(ratchetedKeySet, keyIndex, true);
|
438
|
+
// decryption was successful, set the new key index to reflect the ratcheted key set
|
439
|
+
this.keys.setCurrentKeyIndex(keyIndex);
|
440
|
+
}
|
437
441
|
}
|
438
442
|
return frame;
|
439
443
|
} else {
|
440
444
|
/**
|
441
|
-
*
|
442
|
-
*
|
443
|
-
*
|
444
|
-
* we come back to the initial key.
|
445
|
+
* Because we only set a new key once decryption has been successful,
|
446
|
+
* we can be sure that we don't need to reset the key to the initial material at this point
|
447
|
+
* as the key has not been updated on the keyHandler instance
|
445
448
|
*/
|
446
|
-
if (initialMaterial) {
|
447
|
-
workerLogger.debug('resetting to initial material');
|
448
|
-
this.keys.setKeyFromMaterial(initialMaterial.material, keyIndex);
|
449
|
-
}
|
450
449
|
|
451
450
|
workerLogger.warn('maximum ratchet attempts exceeded');
|
452
451
|
throw new CryptorError(
|
@@ -138,12 +138,11 @@ export class ParticipantKeyHandler extends (EventEmitter as new () => TypedEvent
|
|
138
138
|
* also updates the currentKeyIndex
|
139
139
|
*/
|
140
140
|
async setKeyFromMaterial(material: CryptoKey, keyIndex = 0, emitRatchetEvent = false) {
|
141
|
-
|
142
|
-
|
143
|
-
this.currentKeyIndex = keyIndex % this.cryptoKeyRing.length;
|
144
|
-
}
|
141
|
+
const newIndex = keyIndex >= 0 ? keyIndex % this.cryptoKeyRing.length : -1;
|
142
|
+
workerLogger.debug(`setting new key with index ${newIndex}`);
|
145
143
|
const keySet = await deriveKeys(material, this.keyProviderOptions.ratchetSalt);
|
146
|
-
this.setKeySet(keySet, this.currentKeyIndex, emitRatchetEvent);
|
144
|
+
this.setKeySet(keySet, newIndex >= 0 ? newIndex : this.currentKeyIndex, emitRatchetEvent);
|
145
|
+
if (newIndex >= 0) this.currentKeyIndex = newIndex;
|
147
146
|
}
|
148
147
|
|
149
148
|
setKeySet(keySet: KeySet, keyIndex: number, emitRatchetEvent = false) {
|
@@ -75,7 +75,9 @@ onmessage = (ev) => {
|
|
75
75
|
workerLogger.warn('set shared key');
|
76
76
|
setSharedKey(data.key, data.keyIndex);
|
77
77
|
} else if (data.participantIdentity) {
|
78
|
-
workerLogger.warn(
|
78
|
+
workerLogger.warn(
|
79
|
+
`set participant sender key ${data.participantIdentity} index ${data.keyIndex}`,
|
80
|
+
);
|
79
81
|
getParticipantKeyHandler(data.participantIdentity).setKey(data.key, data.keyIndex);
|
80
82
|
} else {
|
81
83
|
workerLogger.error('no participant Id was provided and shared key usage is disabled');
|
@@ -12,7 +12,7 @@
|
|
12
12
|
// See the License for the specific language governing permissions and
|
13
13
|
// limitations under the License.
|
14
14
|
|
15
|
-
// @generated by protoc-gen-es v1.3.
|
15
|
+
// @generated by protoc-gen-es v1.3.3 with parameter "target=ts"
|
16
16
|
// @generated from file livekit_models.proto (package livekit, syntax proto3)
|
17
17
|
/* eslint-disable */
|
18
18
|
// @ts-nocheck
|
@@ -84,6 +84,26 @@ proto3.util.setEnumType(VideoCodec, "livekit.VideoCodec", [
|
|
84
84
|
{ no: 4, name: "VP8" },
|
85
85
|
]);
|
86
86
|
|
87
|
+
/**
|
88
|
+
* @generated from enum livekit.ImageCodec
|
89
|
+
*/
|
90
|
+
export enum ImageCodec {
|
91
|
+
/**
|
92
|
+
* @generated from enum value: IC_DEFAULT = 0;
|
93
|
+
*/
|
94
|
+
IC_DEFAULT = 0,
|
95
|
+
|
96
|
+
/**
|
97
|
+
* @generated from enum value: IC_JPEG = 1;
|
98
|
+
*/
|
99
|
+
IC_JPEG = 1,
|
100
|
+
}
|
101
|
+
// Retrieve enum metadata with: proto3.getEnumType(ImageCodec)
|
102
|
+
proto3.util.setEnumType(ImageCodec, "livekit.ImageCodec", [
|
103
|
+
{ no: 0, name: "IC_DEFAULT" },
|
104
|
+
{ no: 1, name: "IC_JPEG" },
|
105
|
+
]);
|
106
|
+
|
87
107
|
/**
|
88
108
|
* @generated from enum livekit.TrackType
|
89
109
|
*/
|
@@ -411,11 +431,6 @@ export class Room extends Message<Room> {
|
|
411
431
|
*/
|
412
432
|
activeRecording = false;
|
413
433
|
|
414
|
-
/**
|
415
|
-
* @generated from field: livekit.PlayoutDelay playout_delay = 12;
|
416
|
-
*/
|
417
|
-
playoutDelay?: PlayoutDelay;
|
418
|
-
|
419
434
|
constructor(data?: PartialMessage<Room>) {
|
420
435
|
super();
|
421
436
|
proto3.util.initPartial(data, this);
|
@@ -435,7 +450,6 @@ export class Room extends Message<Room> {
|
|
435
450
|
{ no: 9, name: "num_participants", kind: "scalar", T: 13 /* ScalarType.UINT32 */ },
|
436
451
|
{ no: 11, name: "num_publishers", kind: "scalar", T: 13 /* ScalarType.UINT32 */ },
|
437
452
|
{ no: 10, name: "active_recording", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
|
438
|
-
{ no: 12, name: "playout_delay", kind: "message", T: PlayoutDelay },
|
439
453
|
]);
|
440
454
|
|
441
455
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Room {
|
@@ -1282,6 +1296,11 @@ export class UserPacket extends Message<UserPacket> {
|
|
1282
1296
|
*/
|
1283
1297
|
participantSid = "";
|
1284
1298
|
|
1299
|
+
/**
|
1300
|
+
* @generated from field: string participant_identity = 5;
|
1301
|
+
*/
|
1302
|
+
participantIdentity = "";
|
1303
|
+
|
1285
1304
|
/**
|
1286
1305
|
* user defined payload
|
1287
1306
|
*
|
@@ -1290,12 +1309,19 @@ export class UserPacket extends Message<UserPacket> {
|
|
1290
1309
|
payload = new Uint8Array(0);
|
1291
1310
|
|
1292
1311
|
/**
|
1293
|
-
* the ID of the participants who will receive the message (
|
1312
|
+
* the ID of the participants who will receive the message (sent to all by default)
|
1294
1313
|
*
|
1295
1314
|
* @generated from field: repeated string destination_sids = 3;
|
1296
1315
|
*/
|
1297
1316
|
destinationSids: string[] = [];
|
1298
1317
|
|
1318
|
+
/**
|
1319
|
+
* identities of participants who will receive the message (sent to all by default)
|
1320
|
+
*
|
1321
|
+
* @generated from field: repeated string destination_identities = 6;
|
1322
|
+
*/
|
1323
|
+
destinationIdentities: string[] = [];
|
1324
|
+
|
1299
1325
|
/**
|
1300
1326
|
* topic under which the message was published
|
1301
1327
|
*
|
@@ -1312,8 +1338,10 @@ export class UserPacket extends Message<UserPacket> {
|
|
1312
1338
|
static readonly typeName = "livekit.UserPacket";
|
1313
1339
|
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
1314
1340
|
{ no: 1, name: "participant_sid", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
1341
|
+
{ no: 5, name: "participant_identity", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
1315
1342
|
{ no: 2, name: "payload", kind: "scalar", T: 12 /* ScalarType.BYTES */ },
|
1316
1343
|
{ no: 3, name: "destination_sids", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true },
|
1344
|
+
{ no: 6, name: "destination_identities", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true },
|
1317
1345
|
{ no: 4, name: "topic", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true },
|
1318
1346
|
]);
|
1319
1347
|
|
@@ -1613,6 +1641,16 @@ export enum ClientInfo_SDK {
|
|
1613
1641
|
* @generated from enum value: RUST = 8;
|
1614
1642
|
*/
|
1615
1643
|
RUST = 8,
|
1644
|
+
|
1645
|
+
/**
|
1646
|
+
* @generated from enum value: PYTHON = 9;
|
1647
|
+
*/
|
1648
|
+
PYTHON = 9,
|
1649
|
+
|
1650
|
+
/**
|
1651
|
+
* @generated from enum value: CPP = 10;
|
1652
|
+
*/
|
1653
|
+
CPP = 10,
|
1616
1654
|
}
|
1617
1655
|
// Retrieve enum metadata with: proto3.getEnumType(ClientInfo_SDK)
|
1618
1656
|
proto3.util.setEnumType(ClientInfo_SDK, "livekit.ClientInfo.SDK", [
|
@@ -1625,6 +1663,8 @@ proto3.util.setEnumType(ClientInfo_SDK, "livekit.ClientInfo.SDK", [
|
|
1625
1663
|
{ no: 6, name: "UNITY" },
|
1626
1664
|
{ no: 7, name: "REACT_NATIVE" },
|
1627
1665
|
{ no: 8, name: "RUST" },
|
1666
|
+
{ no: 9, name: "PYTHON" },
|
1667
|
+
{ no: 10, name: "CPP" },
|
1628
1668
|
]);
|
1629
1669
|
|
1630
1670
|
/**
|
@@ -1774,6 +1814,91 @@ export class DisabledCodecs extends Message<DisabledCodecs> {
|
|
1774
1814
|
}
|
1775
1815
|
}
|
1776
1816
|
|
1817
|
+
/**
|
1818
|
+
* @generated from message livekit.RTPDrift
|
1819
|
+
*/
|
1820
|
+
export class RTPDrift extends Message<RTPDrift> {
|
1821
|
+
/**
|
1822
|
+
* @generated from field: google.protobuf.Timestamp start_time = 1;
|
1823
|
+
*/
|
1824
|
+
startTime?: Timestamp;
|
1825
|
+
|
1826
|
+
/**
|
1827
|
+
* @generated from field: google.protobuf.Timestamp end_time = 2;
|
1828
|
+
*/
|
1829
|
+
endTime?: Timestamp;
|
1830
|
+
|
1831
|
+
/**
|
1832
|
+
* @generated from field: double duration = 3;
|
1833
|
+
*/
|
1834
|
+
duration = 0;
|
1835
|
+
|
1836
|
+
/**
|
1837
|
+
* @generated from field: uint64 start_timestamp = 4;
|
1838
|
+
*/
|
1839
|
+
startTimestamp = protoInt64.zero;
|
1840
|
+
|
1841
|
+
/**
|
1842
|
+
* @generated from field: uint64 end_timestamp = 5;
|
1843
|
+
*/
|
1844
|
+
endTimestamp = protoInt64.zero;
|
1845
|
+
|
1846
|
+
/**
|
1847
|
+
* @generated from field: uint64 rtp_clock_ticks = 6;
|
1848
|
+
*/
|
1849
|
+
rtpClockTicks = protoInt64.zero;
|
1850
|
+
|
1851
|
+
/**
|
1852
|
+
* @generated from field: int64 drift_samples = 7;
|
1853
|
+
*/
|
1854
|
+
driftSamples = protoInt64.zero;
|
1855
|
+
|
1856
|
+
/**
|
1857
|
+
* @generated from field: double drift_ms = 8;
|
1858
|
+
*/
|
1859
|
+
driftMs = 0;
|
1860
|
+
|
1861
|
+
/**
|
1862
|
+
* @generated from field: double clock_rate = 9;
|
1863
|
+
*/
|
1864
|
+
clockRate = 0;
|
1865
|
+
|
1866
|
+
constructor(data?: PartialMessage<RTPDrift>) {
|
1867
|
+
super();
|
1868
|
+
proto3.util.initPartial(data, this);
|
1869
|
+
}
|
1870
|
+
|
1871
|
+
static readonly runtime: typeof proto3 = proto3;
|
1872
|
+
static readonly typeName = "livekit.RTPDrift";
|
1873
|
+
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
1874
|
+
{ no: 1, name: "start_time", kind: "message", T: Timestamp },
|
1875
|
+
{ no: 2, name: "end_time", kind: "message", T: Timestamp },
|
1876
|
+
{ no: 3, name: "duration", kind: "scalar", T: 1 /* ScalarType.DOUBLE */ },
|
1877
|
+
{ no: 4, name: "start_timestamp", kind: "scalar", T: 4 /* ScalarType.UINT64 */ },
|
1878
|
+
{ no: 5, name: "end_timestamp", kind: "scalar", T: 4 /* ScalarType.UINT64 */ },
|
1879
|
+
{ no: 6, name: "rtp_clock_ticks", kind: "scalar", T: 4 /* ScalarType.UINT64 */ },
|
1880
|
+
{ no: 7, name: "drift_samples", kind: "scalar", T: 3 /* ScalarType.INT64 */ },
|
1881
|
+
{ no: 8, name: "drift_ms", kind: "scalar", T: 1 /* ScalarType.DOUBLE */ },
|
1882
|
+
{ no: 9, name: "clock_rate", kind: "scalar", T: 1 /* ScalarType.DOUBLE */ },
|
1883
|
+
]);
|
1884
|
+
|
1885
|
+
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): RTPDrift {
|
1886
|
+
return new RTPDrift().fromBinary(bytes, options);
|
1887
|
+
}
|
1888
|
+
|
1889
|
+
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): RTPDrift {
|
1890
|
+
return new RTPDrift().fromJson(jsonValue, options);
|
1891
|
+
}
|
1892
|
+
|
1893
|
+
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): RTPDrift {
|
1894
|
+
return new RTPDrift().fromJsonString(jsonString, options);
|
1895
|
+
}
|
1896
|
+
|
1897
|
+
static equals(a: RTPDrift | PlainMessage<RTPDrift> | undefined, b: RTPDrift | PlainMessage<RTPDrift> | undefined): boolean {
|
1898
|
+
return proto3.util.equals(RTPDrift, a, b);
|
1899
|
+
}
|
1900
|
+
}
|
1901
|
+
|
1777
1902
|
/**
|
1778
1903
|
* @generated from message livekit.RTPStats
|
1779
1904
|
*/
|
@@ -1984,16 +2109,16 @@ export class RTPStats extends Message<RTPStats> {
|
|
1984
2109
|
lastLayerLockPli?: Timestamp;
|
1985
2110
|
|
1986
2111
|
/**
|
1987
|
-
* @generated from field:
|
2112
|
+
* @generated from field: livekit.RTPDrift packet_drift = 44;
|
1988
2113
|
*/
|
1989
|
-
|
2114
|
+
packetDrift?: RTPDrift;
|
1990
2115
|
|
1991
2116
|
/**
|
1992
|
-
* NEXT_ID:
|
2117
|
+
* NEXT_ID: 46
|
1993
2118
|
*
|
1994
|
-
* @generated from field:
|
2119
|
+
* @generated from field: livekit.RTPDrift report_drift = 45;
|
1995
2120
|
*/
|
1996
|
-
|
2121
|
+
reportDrift?: RTPDrift;
|
1997
2122
|
|
1998
2123
|
constructor(data?: PartialMessage<RTPStats>) {
|
1999
2124
|
super();
|
@@ -2044,8 +2169,8 @@ export class RTPStats extends Message<RTPStats> {
|
|
2044
2169
|
{ no: 34, name: "last_key_frame", kind: "message", T: Timestamp },
|
2045
2170
|
{ no: 35, name: "layer_lock_plis", kind: "scalar", T: 13 /* ScalarType.UINT32 */ },
|
2046
2171
|
{ no: 36, name: "last_layer_lock_pli", kind: "message", T: Timestamp },
|
2047
|
-
{ no:
|
2048
|
-
{ no:
|
2172
|
+
{ no: 44, name: "packet_drift", kind: "message", T: RTPDrift },
|
2173
|
+
{ no: 45, name: "report_drift", kind: "message", T: RTPDrift },
|
2049
2174
|
]);
|
2050
2175
|
|
2051
2176
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): RTPStats {
|
@@ -12,7 +12,7 @@
|
|
12
12
|
// See the License for the specific language governing permissions and
|
13
13
|
// limitations under the License.
|
14
14
|
|
15
|
-
// @generated by protoc-gen-es v1.3.
|
15
|
+
// @generated by protoc-gen-es v1.3.3 with parameter "target=ts"
|
16
16
|
// @generated from file livekit_rtc.proto (package livekit, syntax proto3)
|
17
17
|
/* eslint-disable */
|
18
18
|
// @ts-nocheck
|
@@ -487,11 +487,6 @@ export class SimulcastCodec extends Message<SimulcastCodec> {
|
|
487
487
|
*/
|
488
488
|
cid = "";
|
489
489
|
|
490
|
-
/**
|
491
|
-
* @generated from field: bool enable_simulcast_layers = 3;
|
492
|
-
*/
|
493
|
-
enableSimulcastLayers = false;
|
494
|
-
|
495
490
|
constructor(data?: PartialMessage<SimulcastCodec>) {
|
496
491
|
super();
|
497
492
|
proto3.util.initPartial(data, this);
|
@@ -502,7 +497,6 @@ export class SimulcastCodec extends Message<SimulcastCodec> {
|
|
502
497
|
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
503
498
|
{ no: 1, name: "codec", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
504
499
|
{ no: 2, name: "cid", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
505
|
-
{ no: 3, name: "enable_simulcast_layers", kind: "scalar", T: 8 /* ScalarType.BOOL */ },
|
506
500
|
]);
|
507
501
|
|
508
502
|
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): SimulcastCodec {
|
package/src/room/PCTransport.ts
CHANGED
@@ -32,7 +32,7 @@ export const PCEvents = {
|
|
32
32
|
export default class PCTransport extends EventEmitter {
|
33
33
|
private _pc: RTCPeerConnection | null;
|
34
34
|
|
35
|
-
|
35
|
+
private get pc() {
|
36
36
|
if (this._pc) return this._pc;
|
37
37
|
throw new UnexpectedConnectionState('Expected peer connection to be available');
|
38
38
|
}
|
@@ -51,12 +51,38 @@ export default class PCTransport extends EventEmitter {
|
|
51
51
|
|
52
52
|
onOffer?: (offer: RTCSessionDescriptionInit) => void;
|
53
53
|
|
54
|
+
onIceCandidate?: (candidate: RTCIceCandidate) => void;
|
55
|
+
|
56
|
+
onIceCandidateError?: (ev: Event) => void;
|
57
|
+
|
58
|
+
onConnectionStateChange?: (state: RTCPeerConnectionState) => void;
|
59
|
+
|
60
|
+
onDataChannel?: (ev: RTCDataChannelEvent) => void;
|
61
|
+
|
62
|
+
onTrack?: (ev: RTCTrackEvent) => void;
|
63
|
+
|
54
64
|
constructor(config?: RTCConfiguration, mediaConstraints: Record<string, unknown> = {}) {
|
55
65
|
super();
|
56
66
|
this._pc = isChromiumBased()
|
57
67
|
? // @ts-expect-error chrome allows additional media constraints to be passed into the RTCPeerConnection constructor
|
58
68
|
new RTCPeerConnection(config, mediaConstraints)
|
59
69
|
: new RTCPeerConnection(config);
|
70
|
+
this._pc.onicecandidate = (ev) => {
|
71
|
+
if (!ev.candidate) return;
|
72
|
+
this.onIceCandidate?.(ev.candidate);
|
73
|
+
};
|
74
|
+
this._pc.onicecandidateerror = (ev) => {
|
75
|
+
this.onIceCandidateError?.(ev);
|
76
|
+
};
|
77
|
+
this._pc.onconnectionstatechange = () => {
|
78
|
+
this.onConnectionStateChange?.(this._pc?.connectionState ?? 'closed');
|
79
|
+
};
|
80
|
+
this._pc.ondatachannel = (ev) => {
|
81
|
+
this.onDataChannel?.(ev);
|
82
|
+
};
|
83
|
+
this._pc.ontrack = (ev) => {
|
84
|
+
this.onTrack?.(ev);
|
85
|
+
};
|
60
86
|
}
|
61
87
|
|
62
88
|
get isICEConnected(): boolean {
|
@@ -230,7 +256,9 @@ export default class PCTransport extends EventEmitter {
|
|
230
256
|
for (const fmtp of media.fmtp) {
|
231
257
|
if (fmtp.payload === codecPayload) {
|
232
258
|
if (!fmtp.config.includes('x-google-start-bitrate')) {
|
233
|
-
fmtp.config += `;x-google-start-bitrate=${
|
259
|
+
fmtp.config += `;x-google-start-bitrate=${Math.round(
|
260
|
+
trackbr.maxbr * startBitrateForSVC,
|
261
|
+
)}`;
|
234
262
|
}
|
235
263
|
if (!fmtp.config.includes('x-google-max-bitrate')) {
|
236
264
|
fmtp.config += `;x-google-max-bitrate=${trackbr.maxbr}`;
|
@@ -243,9 +271,9 @@ export default class PCTransport extends EventEmitter {
|
|
243
271
|
if (!fmtpFound) {
|
244
272
|
media.fmtp.push({
|
245
273
|
payload: codecPayload,
|
246
|
-
config: `x-google-start-bitrate=${
|
247
|
-
trackbr.maxbr * startBitrateForSVC
|
248
|
-
};x-google-max-bitrate=${trackbr.maxbr}`,
|
274
|
+
config: `x-google-start-bitrate=${Math.round(
|
275
|
+
trackbr.maxbr * startBitrateForSVC,
|
276
|
+
)};x-google-max-bitrate=${trackbr.maxbr}`,
|
249
277
|
});
|
250
278
|
}
|
251
279
|
|
@@ -270,10 +298,99 @@ export default class PCTransport extends EventEmitter {
|
|
270
298
|
return answer;
|
271
299
|
}
|
272
300
|
|
301
|
+
createDataChannel(label: string, dataChannelDict: RTCDataChannelInit) {
|
302
|
+
return this.pc.createDataChannel(label, dataChannelDict);
|
303
|
+
}
|
304
|
+
|
305
|
+
addTransceiver(mediaStreamTrack: MediaStreamTrack, transceiverInit: RTCRtpTransceiverInit) {
|
306
|
+
return this.pc.addTransceiver(mediaStreamTrack, transceiverInit);
|
307
|
+
}
|
308
|
+
|
309
|
+
addTrack(track: MediaStreamTrack) {
|
310
|
+
return this.pc.addTrack(track);
|
311
|
+
}
|
312
|
+
|
273
313
|
setTrackCodecBitrate(info: TrackBitrateInfo) {
|
274
314
|
this.trackBitrates.push(info);
|
275
315
|
}
|
276
316
|
|
317
|
+
setConfiguration(rtcConfig: RTCConfiguration) {
|
318
|
+
return this.pc.setConfiguration(rtcConfig);
|
319
|
+
}
|
320
|
+
|
321
|
+
canRemoveTrack(): boolean {
|
322
|
+
return !!this.pc.removeTrack;
|
323
|
+
}
|
324
|
+
|
325
|
+
removeTrack(sender: RTCRtpSender) {
|
326
|
+
return this.pc.removeTrack(sender);
|
327
|
+
}
|
328
|
+
|
329
|
+
getConnectionState() {
|
330
|
+
return this.pc.connectionState;
|
331
|
+
}
|
332
|
+
|
333
|
+
getICEConnectionState() {
|
334
|
+
return this.pc.iceConnectionState;
|
335
|
+
}
|
336
|
+
|
337
|
+
getSignallingState() {
|
338
|
+
return this.pc.signalingState;
|
339
|
+
}
|
340
|
+
|
341
|
+
getTransceivers() {
|
342
|
+
return this.pc.getTransceivers();
|
343
|
+
}
|
344
|
+
|
345
|
+
getSenders() {
|
346
|
+
return this.pc.getSenders();
|
347
|
+
}
|
348
|
+
|
349
|
+
getLocalDescription() {
|
350
|
+
return this.pc.localDescription;
|
351
|
+
}
|
352
|
+
|
353
|
+
getRemoteDescription() {
|
354
|
+
return this.pc.remoteDescription;
|
355
|
+
}
|
356
|
+
|
357
|
+
async getConnectedAddress(): Promise<string | undefined> {
|
358
|
+
if (!this._pc) {
|
359
|
+
return;
|
360
|
+
}
|
361
|
+
let selectedCandidatePairId = '';
|
362
|
+
const candidatePairs = new Map<string, RTCIceCandidatePairStats>();
|
363
|
+
// id -> candidate ip
|
364
|
+
const candidates = new Map<string, string>();
|
365
|
+
const stats: RTCStatsReport = await this._pc.getStats();
|
366
|
+
stats.forEach((v) => {
|
367
|
+
switch (v.type) {
|
368
|
+
case 'transport':
|
369
|
+
selectedCandidatePairId = v.selectedCandidatePairId;
|
370
|
+
break;
|
371
|
+
case 'candidate-pair':
|
372
|
+
if (selectedCandidatePairId === '' && v.selected) {
|
373
|
+
selectedCandidatePairId = v.id;
|
374
|
+
}
|
375
|
+
candidatePairs.set(v.id, v);
|
376
|
+
break;
|
377
|
+
case 'remote-candidate':
|
378
|
+
candidates.set(v.id, `${v.address}:${v.port}`);
|
379
|
+
break;
|
380
|
+
default:
|
381
|
+
}
|
382
|
+
});
|
383
|
+
|
384
|
+
if (selectedCandidatePairId === '') {
|
385
|
+
return undefined;
|
386
|
+
}
|
387
|
+
const selectedID = candidatePairs.get(selectedCandidatePairId)?.remoteCandidateId;
|
388
|
+
if (selectedID === undefined) {
|
389
|
+
return undefined;
|
390
|
+
}
|
391
|
+
return candidates.get(selectedID);
|
392
|
+
}
|
393
|
+
|
277
394
|
close() {
|
278
395
|
if (!this._pc) {
|
279
396
|
return;
|