livekit-client 2.18.0 → 2.18.2
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 +8 -7
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +8026 -5883
- 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/api/SignalClient.d.ts +12 -4
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/connectionHelper/ConnectionCheck.d.ts +1 -1
- package/dist/src/connectionHelper/ConnectionCheck.d.ts.map +1 -1
- package/dist/src/e2ee/constants.d.ts.map +1 -1
- package/dist/src/e2ee/types.d.ts +6 -0
- package/dist/src/e2ee/types.d.ts.map +1 -1
- package/dist/src/e2ee/utils.d.ts +2 -1
- package/dist/src/e2ee/utils.d.ts.map +1 -1
- package/dist/src/e2ee/worker/DataCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/index.d.ts +6 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts +5 -0
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/PCTransportManager.d.ts +1 -1
- package/dist/src/room/PCTransportManager.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts +28 -11
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +14 -3
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts +5 -1
- package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts.map +1 -1
- package/dist/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts.map +1 -1
- package/dist/src/room/data-track/LocalDataTrack.d.ts +28 -5
- package/dist/src/room/data-track/LocalDataTrack.d.ts.map +1 -1
- package/dist/src/room/data-track/RemoteDataTrack.d.ts +5 -5
- package/dist/src/room/data-track/RemoteDataTrack.d.ts.map +1 -1
- package/dist/src/room/data-track/depacketizer.d.ts +4 -4
- package/dist/src/room/data-track/depacketizer.d.ts.map +1 -1
- package/dist/src/room/data-track/frame.d.ts +14 -0
- package/dist/src/room/data-track/frame.d.ts.map +1 -1
- package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts +19 -11
- package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts.map +1 -1
- package/dist/src/room/data-track/incoming/pipeline.d.ts +6 -5
- package/dist/src/room/data-track/incoming/pipeline.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +57 -23
- package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/errors.d.ts +16 -6
- package/dist/src/room/data-track/outgoing/errors.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/pipeline.d.ts +7 -6
- package/dist/src/room/data-track/outgoing/pipeline.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/types.d.ts +14 -4
- package/dist/src/room/data-track/outgoing/types.d.ts.map +1 -1
- package/dist/src/room/data-track/packet/extensions.d.ts.map +1 -1
- package/dist/src/room/data-track/packetizer.d.ts +4 -4
- package/dist/src/room/data-track/packetizer.d.ts.map +1 -1
- package/dist/src/room/data-track/track-interfaces.d.ts +1 -1
- package/dist/src/room/data-track/track-interfaces.d.ts.map +1 -1
- package/dist/src/room/data-track/types.d.ts +6 -1
- package/dist/src/room/data-track/types.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +24 -3
- package/dist/src/room/events.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +12 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/RemoteParticipant.d.ts +13 -0
- package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +1 -0
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/src/utils/deferrable-map.d.ts +32 -0
- package/dist/src/utils/deferrable-map.d.ts.map +1 -0
- package/dist/src/utils/serializer.d.ts +48 -0
- package/dist/src/utils/serializer.d.ts.map +1 -0
- package/dist/ts4.2/api/SignalClient.d.ts +12 -4
- package/dist/ts4.2/connectionHelper/ConnectionCheck.d.ts +2 -1
- package/dist/ts4.2/e2ee/types.d.ts +6 -0
- package/dist/ts4.2/e2ee/utils.d.ts +2 -1
- package/dist/ts4.2/index.d.ts +7 -4
- package/dist/ts4.2/room/PCTransport.d.ts +5 -0
- package/dist/ts4.2/room/PCTransportManager.d.ts +1 -1
- package/dist/ts4.2/room/RTCEngine.d.ts +28 -11
- package/dist/ts4.2/room/Room.d.ts +14 -3
- package/dist/ts4.2/room/data-stream/incoming/IncomingDataStreamManager.d.ts +5 -1
- package/dist/ts4.2/room/data-track/LocalDataTrack.d.ts +27 -4
- package/dist/ts4.2/room/data-track/RemoteDataTrack.d.ts +4 -4
- package/dist/ts4.2/room/data-track/depacketizer.d.ts +4 -4
- package/dist/ts4.2/room/data-track/frame.d.ts +14 -0
- package/dist/ts4.2/room/data-track/incoming/IncomingDataTrackManager.d.ts +21 -10
- package/dist/ts4.2/room/data-track/incoming/pipeline.d.ts +6 -5
- package/dist/ts4.2/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +57 -23
- package/dist/ts4.2/room/data-track/outgoing/errors.d.ts +16 -6
- package/dist/ts4.2/room/data-track/outgoing/pipeline.d.ts +7 -6
- package/dist/ts4.2/room/data-track/outgoing/types.d.ts +14 -4
- package/dist/ts4.2/room/data-track/packetizer.d.ts +4 -4
- package/dist/ts4.2/room/data-track/track-interfaces.d.ts +1 -1
- package/dist/ts4.2/room/data-track/types.d.ts +6 -1
- package/dist/ts4.2/room/events.d.ts +24 -3
- package/dist/ts4.2/room/participant/LocalParticipant.d.ts +12 -1
- package/dist/ts4.2/room/participant/RemoteParticipant.d.ts +13 -0
- package/dist/ts4.2/room/utils.d.ts +1 -0
- package/dist/ts4.2/utils/deferrable-map.d.ts +32 -0
- package/dist/ts4.2/utils/serializer.d.ts +48 -0
- package/package.json +1 -1
- package/src/api/SignalClient.test.ts +9 -4
- package/src/api/SignalClient.ts +116 -9
- package/src/connectionHelper/ConnectionCheck.ts +1 -1
- package/src/e2ee/constants.ts +1 -0
- package/src/e2ee/types.ts +6 -0
- package/src/e2ee/utils.ts +4 -3
- package/src/e2ee/worker/DataCryptor.ts +1 -4
- package/src/e2ee/worker/FrameCryptor.ts +1 -4
- package/src/e2ee/worker/ParticipantKeyHandler.ts +1 -1
- package/src/index.ts +13 -4
- package/src/room/PCTransport.ts +41 -1
- package/src/room/PCTransportManager.ts +1 -1
- package/src/room/RTCEngine.ts +312 -125
- package/src/room/Room.ts +168 -35
- package/src/room/data-stream/incoming/IncomingDataStreamManager.ts +26 -2
- package/src/room/data-stream/outgoing/OutgoingDataStreamManager.ts +7 -7
- package/src/room/data-track/LocalDataTrack.ts +83 -10
- package/src/room/data-track/RemoteDataTrack.ts +7 -9
- package/src/room/data-track/depacketizer.ts +21 -12
- package/src/room/data-track/frame.ts +28 -2
- package/src/room/data-track/incoming/IncomingDataTrackManager.test.ts +58 -73
- package/src/room/data-track/incoming/IncomingDataTrackManager.ts +139 -80
- package/src/room/data-track/incoming/pipeline.ts +29 -24
- package/src/room/data-track/outgoing/OutgoingDataTrackManager.test.ts +225 -32
- package/src/room/data-track/outgoing/OutgoingDataTrackManager.ts +150 -75
- package/src/room/data-track/outgoing/errors.ts +36 -7
- package/src/room/data-track/outgoing/pipeline.ts +23 -17
- package/src/room/data-track/outgoing/types.ts +12 -3
- package/src/room/data-track/packet/extensions.ts +17 -22
- package/src/room/data-track/packet/index.test.ts +22 -33
- package/src/room/data-track/packetizer.test.ts +2 -2
- package/src/room/data-track/packetizer.ts +4 -4
- package/src/room/data-track/track-interfaces.ts +1 -1
- package/src/room/data-track/types.ts +21 -1
- package/src/room/events.ts +26 -1
- package/src/room/participant/LocalParticipant.ts +74 -8
- package/src/room/participant/RemoteParticipant.ts +25 -0
- package/src/room/utils.ts +4 -0
- package/src/utils/deferrable-map.ts +109 -0
- package/src/utils/serializer.ts +72 -0
- package/dist/src/room/data-track/e2ee.d.ts +0 -12
- package/dist/src/room/data-track/e2ee.d.ts.map +0 -1
- package/dist/ts4.2/room/data-track/e2ee.d.ts +0 -12
- package/src/room/data-track/e2ee.ts +0 -15
|
@@ -72,7 +72,7 @@ describe('DataTrackPacket', () => {
|
|
|
72
72
|
|
|
73
73
|
const packet = new DataTrackPacket(header, payloadBytes);
|
|
74
74
|
|
|
75
|
-
expect(packet.toBinaryLengthBytes()).toStrictEqual(
|
|
75
|
+
expect(packet.toBinaryLengthBytes()).toStrictEqual(74);
|
|
76
76
|
expect(packet.toBinary()).toStrictEqual(
|
|
77
77
|
new Uint8Array([
|
|
78
78
|
0xc, // Version 0, final, extension
|
|
@@ -88,13 +88,11 @@ describe('DataTrackPacket', () => {
|
|
|
88
88
|
17,
|
|
89
89
|
136,
|
|
90
90
|
0, // Rtp oriented extension words (big endian)
|
|
91
|
-
|
|
91
|
+
6,
|
|
92
92
|
|
|
93
93
|
// E2ee extension
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
0, // Length 12 (big endian)
|
|
97
|
-
12,
|
|
94
|
+
1, // ID 1
|
|
95
|
+
13, // Length 13
|
|
98
96
|
0xfa, // Key index
|
|
99
97
|
0x3c, // Iv array
|
|
100
98
|
0x3c,
|
|
@@ -110,10 +108,8 @@ describe('DataTrackPacket', () => {
|
|
|
110
108
|
0x3c,
|
|
111
109
|
|
|
112
110
|
// User timestamp extension
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
0, // Length 7 (big endian)
|
|
116
|
-
7,
|
|
111
|
+
2, // ID 2
|
|
112
|
+
8, // Length 8
|
|
117
113
|
68, // Timestamp value (big endian)
|
|
118
114
|
17,
|
|
119
115
|
34,
|
|
@@ -178,7 +174,7 @@ describe('DataTrackPacket', () => {
|
|
|
178
174
|
|
|
179
175
|
const packet = new DataTrackPacket(header, payloadBytes);
|
|
180
176
|
|
|
181
|
-
expect(packet.toBinaryLengthBytes()).toStrictEqual(
|
|
177
|
+
expect(packet.toBinaryLengthBytes()).toStrictEqual(62);
|
|
182
178
|
expect(packet.toBinary()).toStrictEqual(
|
|
183
179
|
new Uint8Array([
|
|
184
180
|
0x14, // Version 0, start, extension
|
|
@@ -194,13 +190,11 @@ describe('DataTrackPacket', () => {
|
|
|
194
190
|
0,
|
|
195
191
|
104,
|
|
196
192
|
0, // RTP oriented extension words (big endian)
|
|
197
|
-
|
|
193
|
+
3,
|
|
198
194
|
|
|
199
195
|
// E2ee extension
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
0, // Length 12 (big endian)
|
|
203
|
-
12,
|
|
196
|
+
1, // ID 1
|
|
197
|
+
13, // Length 13
|
|
204
198
|
0xfa, // Key index
|
|
205
199
|
0x3c, // Iv array
|
|
206
200
|
0x3c,
|
|
@@ -216,8 +210,6 @@ describe('DataTrackPacket', () => {
|
|
|
216
210
|
0x3c,
|
|
217
211
|
|
|
218
212
|
0, // Extension padding
|
|
219
|
-
0,
|
|
220
|
-
0,
|
|
221
213
|
|
|
222
214
|
0xfa, // Payload
|
|
223
215
|
0xfa,
|
|
@@ -431,13 +423,11 @@ describe('DataTrackPacket', () => {
|
|
|
431
423
|
...VALID_PACKET_BYTES,
|
|
432
424
|
|
|
433
425
|
0, // RTP oriented extension words (big endian)
|
|
434
|
-
|
|
426
|
+
3,
|
|
435
427
|
|
|
436
428
|
// E2ee extension
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
0, // Length 12 (big endian)
|
|
440
|
-
12,
|
|
429
|
+
1, // ID 1
|
|
430
|
+
12, // Length 12
|
|
441
431
|
0xfa, // Key index
|
|
442
432
|
0x3c, // Iv array
|
|
443
433
|
0x3c,
|
|
@@ -453,8 +443,6 @@ describe('DataTrackPacket', () => {
|
|
|
453
443
|
0x3c,
|
|
454
444
|
|
|
455
445
|
0, // Padding
|
|
456
|
-
0,
|
|
457
|
-
0,
|
|
458
446
|
]);
|
|
459
447
|
packetBytes[0] |= 1 << EXT_FLAG_SHIFT; // Extension flag
|
|
460
448
|
|
|
@@ -476,10 +464,8 @@ describe('DataTrackPacket', () => {
|
|
|
476
464
|
2,
|
|
477
465
|
|
|
478
466
|
// User timestamp extension
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
0, // Length 7 (big endian)
|
|
482
|
-
7,
|
|
467
|
+
2, // ID 2
|
|
468
|
+
7, // Length 7
|
|
483
469
|
0x44, // Timestamp (big endian)
|
|
484
470
|
0x11,
|
|
485
471
|
0x22,
|
|
@@ -488,6 +474,9 @@ describe('DataTrackPacket', () => {
|
|
|
488
474
|
0x11,
|
|
489
475
|
0x88,
|
|
490
476
|
0x11,
|
|
477
|
+
|
|
478
|
+
0, // Padding
|
|
479
|
+
0,
|
|
491
480
|
]);
|
|
492
481
|
packetBytes[0] |= 1 << EXT_FLAG_SHIFT; // Extension flag
|
|
493
482
|
|
|
@@ -508,19 +497,19 @@ describe('DataTrackPacket', () => {
|
|
|
508
497
|
2,
|
|
509
498
|
|
|
510
499
|
// Unknown / potential future extension
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
0, // Length 12 (big endian)
|
|
514
|
-
6,
|
|
500
|
+
8, // ID 8
|
|
501
|
+
6, // Length 6
|
|
515
502
|
0x1, // Payload
|
|
516
503
|
0x2,
|
|
517
504
|
0x3,
|
|
518
505
|
0x4,
|
|
519
506
|
0x5,
|
|
520
507
|
0x6,
|
|
508
|
+
0x0,
|
|
521
509
|
|
|
522
510
|
0x0, // Padding
|
|
523
511
|
0x0,
|
|
512
|
+
0x0,
|
|
524
513
|
]);
|
|
525
514
|
packetBytes[0] |= 1 << EXT_FLAG_SHIFT; // Extension flag
|
|
526
515
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import {
|
|
3
|
+
import { DataTrackFrameInternal } from './frame';
|
|
4
4
|
import { DataTrackHandle } from './handle';
|
|
5
5
|
import { FrameMarker } from './packet';
|
|
6
6
|
import { DataTrackExtensions } from './packet/extensions';
|
|
@@ -90,7 +90,7 @@ describe('DataTrackPacketizer', () => {
|
|
|
90
90
|
])('should test packetizer edge cases', (payloadSizeBytes, mtuSizeBytes, label) => {
|
|
91
91
|
const packetizer = new DataTrackPacketizer(DataTrackHandle.fromNumber(1), mtuSizeBytes);
|
|
92
92
|
|
|
93
|
-
const frame:
|
|
93
|
+
const frame: DataTrackFrameInternal = {
|
|
94
94
|
payload: new Uint8Array(payloadSizeBytes).fill(0xab),
|
|
95
95
|
extensions: new DataTrackExtensions(),
|
|
96
96
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Throws } from '@livekit/throws-transformer/throws';
|
|
2
2
|
import { LivekitReasonedError } from '../errors';
|
|
3
|
-
import { type
|
|
3
|
+
import { type DataTrackFrameInternal } from './frame';
|
|
4
4
|
import { DataTrackHandle } from './handle';
|
|
5
5
|
import { DataTrackPacket, DataTrackPacketHeader, FrameMarker } from './packet';
|
|
6
6
|
import { DataTrackClock, DataTrackTimestamp, WrapAroundUnsignedInt } from './utils';
|
|
@@ -38,7 +38,7 @@ export enum DataTrackPacketizerReason {
|
|
|
38
38
|
MtuTooShort = 0,
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
/** A packetizer takes a {@link
|
|
41
|
+
/** A packetizer takes a {@link DataTrackFrameInternal} as input and generates a series
|
|
42
42
|
* of {@link DataTrackPacket}s for transmission to other clients over webrtc. */
|
|
43
43
|
export default class DataTrackPacketizer {
|
|
44
44
|
private handle: DataTrackHandle;
|
|
@@ -70,13 +70,13 @@ export default class DataTrackPacketizer {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
/** Generates a series of packets for the specified {@link
|
|
73
|
+
/** Generates a series of packets for the specified {@link DataTrackFrameInternal}.
|
|
74
74
|
*
|
|
75
75
|
* NOTE: The return value of this function is a generator, so it can be lazily ran if desired,
|
|
76
76
|
* or converted to an array with {@link Array.from}.
|
|
77
77
|
*/
|
|
78
78
|
*packetize(
|
|
79
|
-
frame:
|
|
79
|
+
frame: DataTrackFrameInternal,
|
|
80
80
|
options?: PacketizeOptions,
|
|
81
81
|
): Throws<Generator<DataTrackPacket>, DataTrackPacketizerError> {
|
|
82
82
|
const frameNumber = this.frameNumber.getThenIncrement();
|
|
@@ -45,7 +45,7 @@ export const DataTrackSymbol: symbol = Symbol.for('lk.data-track');
|
|
|
45
45
|
export interface IDataTrack extends ITrack {
|
|
46
46
|
readonly typeSymbol: typeof DataTrackSymbol;
|
|
47
47
|
|
|
48
|
-
readonly info
|
|
48
|
+
readonly info?: DataTrackInfo;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export function isDataTrack(subject: unknown): subject is IDataTrack {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Encryption_Type, DataTrackInfo as ProtocolDataTrackInfo } from '@livekit/protocol';
|
|
1
2
|
import { type DataTrackHandle } from './handle';
|
|
2
3
|
|
|
3
4
|
export type DataTrackSid = string;
|
|
@@ -6,6 +7,25 @@ export type DataTrackSid = string;
|
|
|
6
7
|
export type DataTrackInfo = {
|
|
7
8
|
sid: DataTrackSid;
|
|
8
9
|
pubHandle: DataTrackHandle;
|
|
9
|
-
name:
|
|
10
|
+
name: string;
|
|
10
11
|
usesE2ee: boolean;
|
|
11
12
|
};
|
|
13
|
+
|
|
14
|
+
export const DataTrackInfo = {
|
|
15
|
+
from(protocolInfo: ProtocolDataTrackInfo): DataTrackInfo {
|
|
16
|
+
return {
|
|
17
|
+
sid: protocolInfo.sid,
|
|
18
|
+
pubHandle: protocolInfo.pubHandle,
|
|
19
|
+
name: protocolInfo.name,
|
|
20
|
+
usesE2ee: protocolInfo.encryption !== Encryption_Type.NONE,
|
|
21
|
+
};
|
|
22
|
+
},
|
|
23
|
+
toProtobuf(info: DataTrackInfo): ProtocolDataTrackInfo {
|
|
24
|
+
return new ProtocolDataTrackInfo({
|
|
25
|
+
sid: info.sid,
|
|
26
|
+
pubHandle: info.pubHandle,
|
|
27
|
+
name: info.name,
|
|
28
|
+
encryption: info.usesE2ee ? Encryption_Type.GCM : Encryption_Type.NONE,
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
};
|
package/src/room/events.ts
CHANGED
|
@@ -332,7 +332,7 @@ export enum RoomEvent {
|
|
|
332
332
|
EncryptionError = 'encryptionError',
|
|
333
333
|
/**
|
|
334
334
|
* Emits whenever the current buffer status of a data channel changes
|
|
335
|
-
* args: (isLow: boolean, kind: [[
|
|
335
|
+
* args: (isLow: boolean, kind: [[DataChannelKind]])
|
|
336
336
|
*/
|
|
337
337
|
DCBufferStatusChanged = 'dcBufferStatusChanged',
|
|
338
338
|
|
|
@@ -352,6 +352,26 @@ export enum RoomEvent {
|
|
|
352
352
|
* fired when the client receives connection metrics from other participants
|
|
353
353
|
*/
|
|
354
354
|
MetricsReceived = 'metricsReceived',
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Emits when a new data track has been published by a downstream participant.
|
|
358
|
+
*/
|
|
359
|
+
DataTrackPublished = 'dataTrackPublished',
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Emits when a new data track has been unpublished by a downstream participant.
|
|
363
|
+
*/
|
|
364
|
+
DataTrackUnpublished = 'dataTrackUnpublished',
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Emits when a new data track has been published locally.
|
|
368
|
+
*/
|
|
369
|
+
LocalDataTrackPublished = 'localDataTrackPublished',
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Emits when a new data track has been unpublished locally.
|
|
373
|
+
*/
|
|
374
|
+
LocalDataTrackUnpublished = 'localDataTrackUnpublished',
|
|
355
375
|
}
|
|
356
376
|
|
|
357
377
|
export enum ParticipantEvent {
|
|
@@ -606,6 +626,11 @@ export enum EngineEvent {
|
|
|
606
626
|
SignalRequestResponse = 'signalRequestResponse',
|
|
607
627
|
SignalConnected = 'signalConnected',
|
|
608
628
|
RoomMoved = 'roomMoved',
|
|
629
|
+
PublishDataTrackResponse = 'publishDataTrackResponse',
|
|
630
|
+
UnPublishDataTrackResponse = 'unPublishDataTrackResponse',
|
|
631
|
+
DataTrackSubscriberHandles = 'dataTrackSubscriberHandles',
|
|
632
|
+
DataTrackPacketReceived = 'dataTrackPacketReceived',
|
|
633
|
+
Joined = 'joined',
|
|
609
634
|
}
|
|
610
635
|
|
|
611
636
|
export enum TrackEvent {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Mutex } from '@livekit/mutex';
|
|
1
2
|
import {
|
|
2
3
|
AddTrackRequest,
|
|
3
4
|
AudioTrackFeature,
|
|
@@ -27,8 +28,13 @@ import type { InternalRoomOptions } from '../../options';
|
|
|
27
28
|
import TypedPromise from '../../utils/TypedPromise';
|
|
28
29
|
import { PCTransportState } from '../PCTransportManager';
|
|
29
30
|
import type RTCEngine from '../RTCEngine';
|
|
31
|
+
import { DataChannelKind } from '../RTCEngine';
|
|
30
32
|
import type OutgoingDataStreamManager from '../data-stream/outgoing/OutgoingDataStreamManager';
|
|
31
33
|
import type { TextStreamWriter } from '../data-stream/outgoing/StreamWriter';
|
|
34
|
+
import LocalDataTrack from '../data-track/LocalDataTrack';
|
|
35
|
+
import type OutgoingDataTrackManager from '../data-track/outgoing/OutgoingDataTrackManager';
|
|
36
|
+
import { DataTrackPublishError } from '../data-track/outgoing/errors';
|
|
37
|
+
import type { DataTrackOptions } from '../data-track/outgoing/types';
|
|
32
38
|
import { defaultVideoCodec } from '../defaults';
|
|
33
39
|
import {
|
|
34
40
|
DeviceUnsupportedError,
|
|
@@ -138,6 +144,8 @@ export default class LocalParticipant extends Participant {
|
|
|
138
144
|
|
|
139
145
|
private encryptionType: Encryption_Type = Encryption_Type.NONE;
|
|
140
146
|
|
|
147
|
+
private e2eeStateMutex = new Mutex();
|
|
148
|
+
|
|
141
149
|
private reconnectFuture?: Future<void, Error>;
|
|
142
150
|
|
|
143
151
|
private signalConnectedFuture?: Future<void, Error>;
|
|
@@ -150,6 +158,8 @@ export default class LocalParticipant extends Participant {
|
|
|
150
158
|
|
|
151
159
|
private roomOutgoingDataStreamManager: OutgoingDataStreamManager;
|
|
152
160
|
|
|
161
|
+
private roomOutgoingDataTrackManager: OutgoingDataTrackManager;
|
|
162
|
+
|
|
153
163
|
private pendingSignalRequests: Map<
|
|
154
164
|
number,
|
|
155
165
|
{
|
|
@@ -179,6 +189,7 @@ export default class LocalParticipant extends Participant {
|
|
|
179
189
|
options: InternalRoomOptions,
|
|
180
190
|
roomRpcHandlers: Map<string, (data: RpcInvocationData) => Promise<string>>,
|
|
181
191
|
roomOutgoingDataStreamManager: OutgoingDataStreamManager,
|
|
192
|
+
roomOutgoingDataTrackManager: OutgoingDataTrackManager,
|
|
182
193
|
) {
|
|
183
194
|
super(sid, identity, undefined, undefined, undefined, {
|
|
184
195
|
loggerName: options.loggerName,
|
|
@@ -198,6 +209,7 @@ export default class LocalParticipant extends Participant {
|
|
|
198
209
|
this.pendingSignalRequests = new Map();
|
|
199
210
|
this.rpcHandlers = roomRpcHandlers;
|
|
200
211
|
this.roomOutgoingDataStreamManager = roomOutgoingDataStreamManager;
|
|
212
|
+
this.roomOutgoingDataTrackManager = roomOutgoingDataTrackManager;
|
|
201
213
|
}
|
|
202
214
|
|
|
203
215
|
get lastCameraError(): Error | undefined {
|
|
@@ -311,6 +323,35 @@ export default class LocalParticipant extends Participant {
|
|
|
311
323
|
}
|
|
312
324
|
this.pendingSignalRequests.delete(requestId);
|
|
313
325
|
}
|
|
326
|
+
|
|
327
|
+
switch (response.request.case) {
|
|
328
|
+
case 'publishDataTrack': {
|
|
329
|
+
let error;
|
|
330
|
+
switch (response.reason) {
|
|
331
|
+
case RequestResponse_Reason.NOT_ALLOWED:
|
|
332
|
+
error = DataTrackPublishError.notAllowed(response.message);
|
|
333
|
+
break;
|
|
334
|
+
case RequestResponse_Reason.DUPLICATE_NAME:
|
|
335
|
+
error = DataTrackPublishError.duplicateName(response.message);
|
|
336
|
+
break;
|
|
337
|
+
case RequestResponse_Reason.INVALID_NAME:
|
|
338
|
+
error = DataTrackPublishError.invalidName(response.message);
|
|
339
|
+
break;
|
|
340
|
+
case RequestResponse_Reason.LIMIT_EXCEEDED:
|
|
341
|
+
error = DataTrackPublishError.limitReached(response.message);
|
|
342
|
+
break;
|
|
343
|
+
default:
|
|
344
|
+
error = DataTrackPublishError.unknown(response.reason, response.message);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
this.roomOutgoingDataTrackManager.receivedSfuPublishResponse(
|
|
349
|
+
response.request.value.pubHandle,
|
|
350
|
+
{ type: 'error', error },
|
|
351
|
+
);
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
314
355
|
};
|
|
315
356
|
|
|
316
357
|
private handleDataPacket = (packet: DataPacket) => {
|
|
@@ -461,8 +502,20 @@ export default class LocalParticipant extends Participant {
|
|
|
461
502
|
|
|
462
503
|
/** @internal */
|
|
463
504
|
async setE2EEEnabled(enabled: boolean) {
|
|
464
|
-
|
|
465
|
-
|
|
505
|
+
const unlock = await this.e2eeStateMutex.lock();
|
|
506
|
+
try {
|
|
507
|
+
this.encryptionType = enabled ? Encryption_Type.GCM : Encryption_Type.NONE;
|
|
508
|
+
await Promise.all(this.pendingPublishPromises.values());
|
|
509
|
+
if (
|
|
510
|
+
this.trackPublications.size === 0 ||
|
|
511
|
+
Array.from(this.trackPublications.values()).every((pub) => pub.isEncrypted === enabled)
|
|
512
|
+
) {
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
await this.republishAllTracks(undefined, false);
|
|
516
|
+
} finally {
|
|
517
|
+
unlock();
|
|
518
|
+
}
|
|
466
519
|
}
|
|
467
520
|
|
|
468
521
|
/**
|
|
@@ -1648,7 +1701,8 @@ export default class LocalParticipant extends Participant {
|
|
|
1648
1701
|
* @param options optionally specify a `reliable`, `topic` and `destination`
|
|
1649
1702
|
*/
|
|
1650
1703
|
async publishData(data: Uint8Array, options: DataPublishOptions = {}): Promise<void> {
|
|
1651
|
-
const kind = options.reliable ?
|
|
1704
|
+
const kind = options.reliable ? DataChannelKind.RELIABLE : DataChannelKind.LOSSY;
|
|
1705
|
+
const dataPacketKind = options.reliable ? DataPacket_Kind.RELIABLE : DataPacket_Kind.LOSSY;
|
|
1652
1706
|
const destinationIdentities = options.destinationIdentities;
|
|
1653
1707
|
const topic = options.topic;
|
|
1654
1708
|
|
|
@@ -1660,7 +1714,7 @@ export default class LocalParticipant extends Participant {
|
|
|
1660
1714
|
});
|
|
1661
1715
|
|
|
1662
1716
|
const packet = new DataPacket({
|
|
1663
|
-
kind:
|
|
1717
|
+
kind: dataPacketKind,
|
|
1664
1718
|
value: {
|
|
1665
1719
|
case: 'user',
|
|
1666
1720
|
value: userPacket,
|
|
@@ -1688,7 +1742,7 @@ export default class LocalParticipant extends Participant {
|
|
|
1688
1742
|
},
|
|
1689
1743
|
});
|
|
1690
1744
|
|
|
1691
|
-
await this.engine.sendDataPacket(packet,
|
|
1745
|
+
await this.engine.sendDataPacket(packet, DataChannelKind.RELIABLE);
|
|
1692
1746
|
}
|
|
1693
1747
|
|
|
1694
1748
|
/** @deprecated Consider migrating to {@link sendText} */
|
|
@@ -1708,7 +1762,7 @@ export default class LocalParticipant extends Participant {
|
|
|
1708
1762
|
}),
|
|
1709
1763
|
},
|
|
1710
1764
|
});
|
|
1711
|
-
await this.engine.sendDataPacket(packet,
|
|
1765
|
+
await this.engine.sendDataPacket(packet, DataChannelKind.RELIABLE);
|
|
1712
1766
|
|
|
1713
1767
|
this.emit(ParticipantEvent.ChatMessage, msg);
|
|
1714
1768
|
return msg;
|
|
@@ -1731,7 +1785,7 @@ export default class LocalParticipant extends Participant {
|
|
|
1731
1785
|
}),
|
|
1732
1786
|
},
|
|
1733
1787
|
});
|
|
1734
|
-
await this.engine.sendDataPacket(packet,
|
|
1788
|
+
await this.engine.sendDataPacket(packet, DataChannelKind.RELIABLE);
|
|
1735
1789
|
this.emit(ParticipantEvent.ChatMessage, msg);
|
|
1736
1790
|
return msg;
|
|
1737
1791
|
}
|
|
@@ -1946,7 +2000,7 @@ export default class LocalParticipant extends Participant {
|
|
|
1946
2000
|
},
|
|
1947
2001
|
});
|
|
1948
2002
|
|
|
1949
|
-
await this.engine.sendDataPacket(packet,
|
|
2003
|
+
await this.engine.sendDataPacket(packet, DataChannelKind.RELIABLE);
|
|
1950
2004
|
}
|
|
1951
2005
|
|
|
1952
2006
|
/** @internal */
|
|
@@ -2235,4 +2289,16 @@ export default class LocalParticipant extends Participant {
|
|
|
2235
2289
|
await sleep(20);
|
|
2236
2290
|
}
|
|
2237
2291
|
}
|
|
2292
|
+
|
|
2293
|
+
/** Publishes a data track.
|
|
2294
|
+
*
|
|
2295
|
+
* Returns the published data track if successful. Use {@link LocalDataTrack#tryPush}
|
|
2296
|
+
* to send data frames on the track.
|
|
2297
|
+
*/
|
|
2298
|
+
async publishDataTrack(options: DataTrackOptions): Promise<LocalDataTrack> {
|
|
2299
|
+
const track = new LocalDataTrack(options, this.roomOutgoingDataTrackManager);
|
|
2300
|
+
await track.publish();
|
|
2301
|
+
|
|
2302
|
+
return track;
|
|
2303
|
+
}
|
|
2238
2304
|
}
|
|
@@ -5,6 +5,8 @@ import type {
|
|
|
5
5
|
UpdateTrackSettings,
|
|
6
6
|
} from '@livekit/protocol';
|
|
7
7
|
import type { SignalClient } from '../../api/SignalClient';
|
|
8
|
+
import { DeferrableMap } from '../../utils/deferrable-map';
|
|
9
|
+
import type RemoteDataTrack from '../data-track/RemoteDataTrack';
|
|
8
10
|
import { ParticipantEvent, TrackEvent } from '../events';
|
|
9
11
|
import RemoteAudioTrack from '../track/RemoteAudioTrack';
|
|
10
12
|
import type RemoteTrack from '../track/RemoteTrack';
|
|
@@ -27,6 +29,14 @@ export default class RemoteParticipant extends Participant {
|
|
|
27
29
|
|
|
28
30
|
trackPublications: Map<string, RemoteTrackPublication>;
|
|
29
31
|
|
|
32
|
+
/** A map of data track name to the corresponding {@link RemoteDataTrack}.
|
|
33
|
+
* @example
|
|
34
|
+
* // An already existing data track:
|
|
35
|
+
* const track = remoteParticipant.dataTracks.get("data track name");
|
|
36
|
+
* // Wait for a data track which will be published soon:
|
|
37
|
+
* const track = await remoteParticipant.dataTracks.getDeferred("data track name"); */
|
|
38
|
+
dataTracks: DeferrableMap<RemoteDataTrack['info']['name'], RemoteDataTrack>;
|
|
39
|
+
|
|
30
40
|
signalClient: SignalClient;
|
|
31
41
|
|
|
32
42
|
private volumeMap: Map<Track.Source, number>;
|
|
@@ -75,6 +85,7 @@ export default class RemoteParticipant extends Participant {
|
|
|
75
85
|
this.trackPublications = new Map();
|
|
76
86
|
this.audioTrackPublications = new Map();
|
|
77
87
|
this.videoTrackPublications = new Map();
|
|
88
|
+
this.dataTracks = new DeferrableMap();
|
|
78
89
|
this.volumeMap = new Map();
|
|
79
90
|
}
|
|
80
91
|
|
|
@@ -376,6 +387,20 @@ export default class RemoteParticipant extends Participant {
|
|
|
376
387
|
await Promise.all(promises);
|
|
377
388
|
}
|
|
378
389
|
|
|
390
|
+
/** @internal */
|
|
391
|
+
addRemoteDataTrack(remoteDataTrack: RemoteDataTrack) {
|
|
392
|
+
this.dataTracks.set(remoteDataTrack.info.name, remoteDataTrack);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/** @internal */
|
|
396
|
+
removeRemoteDataTrack(remoteDataTrackSid: RemoteDataTrack['info']['sid']) {
|
|
397
|
+
for (const [name, dataTrack] of this.dataTracks.entries()) {
|
|
398
|
+
if (remoteDataTrackSid === dataTrack.info.sid) {
|
|
399
|
+
this.dataTracks.delete(name);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
379
404
|
/** @internal */
|
|
380
405
|
emit<E extends keyof ParticipantEventCallbacks>(
|
|
381
406
|
event: E,
|
package/src/room/utils.ts
CHANGED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { type Throws } from '@livekit/throws-transformer/throws';
|
|
2
|
+
import { Future } from '../room/utils';
|
|
3
|
+
|
|
4
|
+
/** An error which is thrown if a {@link DeferrableMap#getDeferred} call is aborted midway
|
|
5
|
+
* through. */
|
|
6
|
+
export class DeferrableMapAbortError extends DOMException {
|
|
7
|
+
reason: unknown;
|
|
8
|
+
|
|
9
|
+
constructor(message: string, reason?: unknown) {
|
|
10
|
+
super(message, 'AbortError');
|
|
11
|
+
this.reason = reason;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A Map-like container keyed by unique strings that supports the ability to wait
|
|
17
|
+
* for future keys to show up in the map.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // An already existing key:
|
|
21
|
+
* const value = map.get("key");
|
|
22
|
+
* // Wait for a key which will be added soon:
|
|
23
|
+
* const value = await map.getDeferred("key");
|
|
24
|
+
*/
|
|
25
|
+
export class DeferrableMap<K, V> extends Map<K, V> {
|
|
26
|
+
private pending: Map<K, Array<Future<V, DeferrableMapAbortError>>> = new Map();
|
|
27
|
+
|
|
28
|
+
set(key: K, value: V): this {
|
|
29
|
+
super.set(key, value);
|
|
30
|
+
|
|
31
|
+
// Resolve any futures waiting on this key.
|
|
32
|
+
const futures = this.pending.get(key);
|
|
33
|
+
if (futures) {
|
|
34
|
+
for (const future of futures) {
|
|
35
|
+
if (!future.isResolved) {
|
|
36
|
+
future.resolve?.(value);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
this.pending.delete(key);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get [Symbol.toStringTag](): string {
|
|
46
|
+
return 'WaitableMap';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Returns the value for `key` immediately if it exists, otherwise returns a
|
|
51
|
+
* promise that resolves once `set(key, value)` is called.
|
|
52
|
+
*
|
|
53
|
+
* If an `AbortSignal` is provided and it is aborted before the key appears,
|
|
54
|
+
* the returned promise rejects with an {@link DeferrableMapAbortError}.
|
|
55
|
+
*/
|
|
56
|
+
getDeferred(key: K): Promise<V>;
|
|
57
|
+
getDeferred(key: K, signal: AbortSignal): Promise<Throws<V, DeferrableMapAbortError>>;
|
|
58
|
+
async getDeferred(key: K, signal?: AbortSignal) {
|
|
59
|
+
const existing = this.get(key);
|
|
60
|
+
if (typeof existing !== 'undefined') {
|
|
61
|
+
return existing;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Bail out immediately if the signal is already aborted.
|
|
65
|
+
if (signal?.aborted) {
|
|
66
|
+
throw new DeferrableMapAbortError('The operation was aborted.', signal.reason);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const future = new Future<V, DeferrableMapAbortError>(undefined, () => {
|
|
70
|
+
// Clean up the pending list when the future settles.
|
|
71
|
+
const futures = this.pending.get(key);
|
|
72
|
+
if (!futures) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const idx = futures.indexOf(future);
|
|
77
|
+
if (idx !== -1) {
|
|
78
|
+
futures.splice(idx, 1);
|
|
79
|
+
}
|
|
80
|
+
if (futures.length === 0) {
|
|
81
|
+
this.pending.delete(key);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const existingFutures = this.pending.get(key);
|
|
86
|
+
if (existingFutures) {
|
|
87
|
+
existingFutures.push(future);
|
|
88
|
+
} else {
|
|
89
|
+
this.pending.set(key, [future]);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// If a signal was provided, listen for abort and reject the future.
|
|
93
|
+
if (signal) {
|
|
94
|
+
const onAbort = () => {
|
|
95
|
+
if (!future.isResolved) {
|
|
96
|
+
future.reject?.(new DeferrableMapAbortError('The operation was aborted.', signal.reason));
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
100
|
+
|
|
101
|
+
// Clean up the listener once the future settles (resolved or rejected).
|
|
102
|
+
future.promise.finally(() => {
|
|
103
|
+
signal.removeEventListener('abort', onAbort);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return future.promise;
|
|
108
|
+
}
|
|
109
|
+
}
|