livekit-client 2.18.0 → 2.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/dist/livekit-client.e2ee.worker.js +1 -1
  2. package/dist/livekit-client.e2ee.worker.js.map +1 -1
  3. package/dist/livekit-client.e2ee.worker.mjs +8 -7
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +7832 -5799
  6. package/dist/livekit-client.esm.mjs.map +1 -1
  7. package/dist/livekit-client.umd.js +1 -1
  8. package/dist/livekit-client.umd.js.map +1 -1
  9. package/dist/src/api/SignalClient.d.ts +12 -4
  10. package/dist/src/api/SignalClient.d.ts.map +1 -1
  11. package/dist/src/e2ee/constants.d.ts.map +1 -1
  12. package/dist/src/e2ee/types.d.ts +6 -0
  13. package/dist/src/e2ee/types.d.ts.map +1 -1
  14. package/dist/src/e2ee/utils.d.ts +2 -1
  15. package/dist/src/e2ee/utils.d.ts.map +1 -1
  16. package/dist/src/e2ee/worker/DataCryptor.d.ts.map +1 -1
  17. package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  18. package/dist/src/index.d.ts +5 -4
  19. package/dist/src/index.d.ts.map +1 -1
  20. package/dist/src/room/PCTransport.d.ts +5 -0
  21. package/dist/src/room/PCTransport.d.ts.map +1 -1
  22. package/dist/src/room/PCTransportManager.d.ts +1 -1
  23. package/dist/src/room/PCTransportManager.d.ts.map +1 -1
  24. package/dist/src/room/RTCEngine.d.ts +24 -8
  25. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  26. package/dist/src/room/Room.d.ts +13 -3
  27. package/dist/src/room/Room.d.ts.map +1 -1
  28. package/dist/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts.map +1 -1
  29. package/dist/src/room/data-track/LocalDataTrack.d.ts +28 -5
  30. package/dist/src/room/data-track/LocalDataTrack.d.ts.map +1 -1
  31. package/dist/src/room/data-track/RemoteDataTrack.d.ts +5 -5
  32. package/dist/src/room/data-track/RemoteDataTrack.d.ts.map +1 -1
  33. package/dist/src/room/data-track/depacketizer.d.ts +4 -4
  34. package/dist/src/room/data-track/depacketizer.d.ts.map +1 -1
  35. package/dist/src/room/data-track/frame.d.ts +14 -0
  36. package/dist/src/room/data-track/frame.d.ts.map +1 -1
  37. package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts +19 -11
  38. package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts.map +1 -1
  39. package/dist/src/room/data-track/incoming/pipeline.d.ts +6 -5
  40. package/dist/src/room/data-track/incoming/pipeline.d.ts.map +1 -1
  41. package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +57 -23
  42. package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts.map +1 -1
  43. package/dist/src/room/data-track/outgoing/errors.d.ts +16 -6
  44. package/dist/src/room/data-track/outgoing/errors.d.ts.map +1 -1
  45. package/dist/src/room/data-track/outgoing/pipeline.d.ts +7 -6
  46. package/dist/src/room/data-track/outgoing/pipeline.d.ts.map +1 -1
  47. package/dist/src/room/data-track/outgoing/types.d.ts +14 -4
  48. package/dist/src/room/data-track/outgoing/types.d.ts.map +1 -1
  49. package/dist/src/room/data-track/packet/extensions.d.ts.map +1 -1
  50. package/dist/src/room/data-track/packetizer.d.ts +4 -4
  51. package/dist/src/room/data-track/packetizer.d.ts.map +1 -1
  52. package/dist/src/room/data-track/track-interfaces.d.ts +1 -1
  53. package/dist/src/room/data-track/track-interfaces.d.ts.map +1 -1
  54. package/dist/src/room/data-track/types.d.ts +6 -1
  55. package/dist/src/room/data-track/types.d.ts.map +1 -1
  56. package/dist/src/room/events.d.ts +24 -3
  57. package/dist/src/room/events.d.ts.map +1 -1
  58. package/dist/src/room/participant/LocalParticipant.d.ts +11 -1
  59. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  60. package/dist/src/room/participant/RemoteParticipant.d.ts +13 -0
  61. package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
  62. package/dist/src/room/utils.d.ts +1 -0
  63. package/dist/src/room/utils.d.ts.map +1 -1
  64. package/dist/src/utils/deferrable-map.d.ts +32 -0
  65. package/dist/src/utils/deferrable-map.d.ts.map +1 -0
  66. package/dist/ts4.2/api/SignalClient.d.ts +12 -4
  67. package/dist/ts4.2/e2ee/types.d.ts +6 -0
  68. package/dist/ts4.2/e2ee/utils.d.ts +2 -1
  69. package/dist/ts4.2/index.d.ts +5 -4
  70. package/dist/ts4.2/room/PCTransport.d.ts +5 -0
  71. package/dist/ts4.2/room/PCTransportManager.d.ts +1 -1
  72. package/dist/ts4.2/room/RTCEngine.d.ts +24 -8
  73. package/dist/ts4.2/room/Room.d.ts +13 -3
  74. package/dist/ts4.2/room/data-track/LocalDataTrack.d.ts +27 -4
  75. package/dist/ts4.2/room/data-track/RemoteDataTrack.d.ts +4 -4
  76. package/dist/ts4.2/room/data-track/depacketizer.d.ts +4 -4
  77. package/dist/ts4.2/room/data-track/frame.d.ts +14 -0
  78. package/dist/ts4.2/room/data-track/incoming/IncomingDataTrackManager.d.ts +21 -10
  79. package/dist/ts4.2/room/data-track/incoming/pipeline.d.ts +6 -5
  80. package/dist/ts4.2/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +57 -23
  81. package/dist/ts4.2/room/data-track/outgoing/errors.d.ts +16 -6
  82. package/dist/ts4.2/room/data-track/outgoing/pipeline.d.ts +7 -6
  83. package/dist/ts4.2/room/data-track/outgoing/types.d.ts +14 -4
  84. package/dist/ts4.2/room/data-track/packetizer.d.ts +4 -4
  85. package/dist/ts4.2/room/data-track/track-interfaces.d.ts +1 -1
  86. package/dist/ts4.2/room/data-track/types.d.ts +6 -1
  87. package/dist/ts4.2/room/events.d.ts +24 -3
  88. package/dist/ts4.2/room/participant/LocalParticipant.d.ts +11 -1
  89. package/dist/ts4.2/room/participant/RemoteParticipant.d.ts +13 -0
  90. package/dist/ts4.2/room/utils.d.ts +1 -0
  91. package/dist/ts4.2/utils/deferrable-map.d.ts +32 -0
  92. package/package.json +1 -1
  93. package/src/api/SignalClient.test.ts +9 -4
  94. package/src/api/SignalClient.ts +116 -9
  95. package/src/e2ee/constants.ts +1 -0
  96. package/src/e2ee/types.ts +6 -0
  97. package/src/e2ee/utils.ts +4 -3
  98. package/src/e2ee/worker/DataCryptor.ts +1 -4
  99. package/src/e2ee/worker/FrameCryptor.ts +1 -4
  100. package/src/e2ee/worker/ParticipantKeyHandler.ts +1 -1
  101. package/src/index.ts +6 -4
  102. package/src/room/PCTransport.ts +41 -1
  103. package/src/room/PCTransportManager.ts +1 -1
  104. package/src/room/RTCEngine.ts +266 -111
  105. package/src/room/Room.ts +149 -12
  106. package/src/room/data-stream/outgoing/OutgoingDataStreamManager.ts +7 -7
  107. package/src/room/data-track/LocalDataTrack.ts +83 -10
  108. package/src/room/data-track/RemoteDataTrack.ts +7 -9
  109. package/src/room/data-track/depacketizer.ts +21 -12
  110. package/src/room/data-track/frame.ts +28 -2
  111. package/src/room/data-track/incoming/IncomingDataTrackManager.test.ts +58 -73
  112. package/src/room/data-track/incoming/IncomingDataTrackManager.ts +132 -80
  113. package/src/room/data-track/incoming/pipeline.ts +29 -24
  114. package/src/room/data-track/outgoing/OutgoingDataTrackManager.test.ts +225 -32
  115. package/src/room/data-track/outgoing/OutgoingDataTrackManager.ts +150 -75
  116. package/src/room/data-track/outgoing/errors.ts +36 -7
  117. package/src/room/data-track/outgoing/pipeline.ts +23 -17
  118. package/src/room/data-track/outgoing/types.ts +12 -3
  119. package/src/room/data-track/packet/extensions.ts +17 -22
  120. package/src/room/data-track/packet/index.test.ts +22 -33
  121. package/src/room/data-track/packetizer.test.ts +2 -2
  122. package/src/room/data-track/packetizer.ts +4 -4
  123. package/src/room/data-track/track-interfaces.ts +1 -1
  124. package/src/room/data-track/types.ts +21 -1
  125. package/src/room/events.ts +26 -1
  126. package/src/room/participant/LocalParticipant.ts +57 -6
  127. package/src/room/participant/RemoteParticipant.ts +25 -0
  128. package/src/room/utils.ts +4 -0
  129. package/src/utils/deferrable-map.ts +109 -0
  130. package/dist/src/room/data-track/e2ee.d.ts +0 -12
  131. package/dist/src/room/data-track/e2ee.d.ts.map +0 -1
  132. package/dist/ts4.2/room/data-track/e2ee.d.ts +0 -12
  133. 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(78);
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
- 7,
91
+ 6,
92
92
 
93
93
  // E2ee extension
94
- 0, // ID 1 (big endian)
95
- 1,
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
- 0, // ID 2 (big endian)
114
- 2,
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(66);
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
- 4,
193
+ 3,
198
194
 
199
195
  // E2ee extension
200
- 0, // ID 1 (big endian)
201
- 1,
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
- 4,
426
+ 3,
435
427
 
436
428
  // E2ee extension
437
- 0, // ID 1 (big endian)
438
- 1,
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
- 0, // ID 2 (big endian)
480
- 2,
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
- 0, // ID 8 (big endian)
512
- 8,
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 { DataTrackFrame } from './frame';
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: DataTrackFrame = {
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 DataTrackFrame } from './frame';
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 DataTrackFrame} as input and generates a series
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 DataTrackPacketizerFrame}.
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: DataTrackFrame,
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: DataTrackInfo;
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: String;
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
+ };
@@ -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: [[DataPacket_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 {
@@ -27,8 +27,13 @@ import type { InternalRoomOptions } from '../../options';
27
27
  import TypedPromise from '../../utils/TypedPromise';
28
28
  import { PCTransportState } from '../PCTransportManager';
29
29
  import type RTCEngine from '../RTCEngine';
30
+ import { DataChannelKind } from '../RTCEngine';
30
31
  import type OutgoingDataStreamManager from '../data-stream/outgoing/OutgoingDataStreamManager';
31
32
  import type { TextStreamWriter } from '../data-stream/outgoing/StreamWriter';
33
+ import LocalDataTrack from '../data-track/LocalDataTrack';
34
+ import type OutgoingDataTrackManager from '../data-track/outgoing/OutgoingDataTrackManager';
35
+ import { DataTrackPublishError } from '../data-track/outgoing/errors';
36
+ import type { DataTrackOptions } from '../data-track/outgoing/types';
32
37
  import { defaultVideoCodec } from '../defaults';
33
38
  import {
34
39
  DeviceUnsupportedError,
@@ -150,6 +155,8 @@ export default class LocalParticipant extends Participant {
150
155
 
151
156
  private roomOutgoingDataStreamManager: OutgoingDataStreamManager;
152
157
 
158
+ private roomOutgoingDataTrackManager: OutgoingDataTrackManager;
159
+
153
160
  private pendingSignalRequests: Map<
154
161
  number,
155
162
  {
@@ -179,6 +186,7 @@ export default class LocalParticipant extends Participant {
179
186
  options: InternalRoomOptions,
180
187
  roomRpcHandlers: Map<string, (data: RpcInvocationData) => Promise<string>>,
181
188
  roomOutgoingDataStreamManager: OutgoingDataStreamManager,
189
+ roomOutgoingDataTrackManager: OutgoingDataTrackManager,
182
190
  ) {
183
191
  super(sid, identity, undefined, undefined, undefined, {
184
192
  loggerName: options.loggerName,
@@ -198,6 +206,7 @@ export default class LocalParticipant extends Participant {
198
206
  this.pendingSignalRequests = new Map();
199
207
  this.rpcHandlers = roomRpcHandlers;
200
208
  this.roomOutgoingDataStreamManager = roomOutgoingDataStreamManager;
209
+ this.roomOutgoingDataTrackManager = roomOutgoingDataTrackManager;
201
210
  }
202
211
 
203
212
  get lastCameraError(): Error | undefined {
@@ -311,6 +320,35 @@ export default class LocalParticipant extends Participant {
311
320
  }
312
321
  this.pendingSignalRequests.delete(requestId);
313
322
  }
323
+
324
+ switch (response.request.case) {
325
+ case 'publishDataTrack': {
326
+ let error;
327
+ switch (response.reason) {
328
+ case RequestResponse_Reason.NOT_ALLOWED:
329
+ error = DataTrackPublishError.notAllowed(response.message);
330
+ break;
331
+ case RequestResponse_Reason.DUPLICATE_NAME:
332
+ error = DataTrackPublishError.duplicateName(response.message);
333
+ break;
334
+ case RequestResponse_Reason.INVALID_NAME:
335
+ error = DataTrackPublishError.invalidName(response.message);
336
+ break;
337
+ case RequestResponse_Reason.LIMIT_EXCEEDED:
338
+ error = DataTrackPublishError.limitReached(response.message);
339
+ break;
340
+ default:
341
+ error = DataTrackPublishError.unknown(response.reason, response.message);
342
+ return;
343
+ }
344
+
345
+ this.roomOutgoingDataTrackManager.receivedSfuPublishResponse(
346
+ response.request.value.pubHandle,
347
+ { type: 'error', error },
348
+ );
349
+ break;
350
+ }
351
+ }
314
352
  };
315
353
 
316
354
  private handleDataPacket = (packet: DataPacket) => {
@@ -1648,7 +1686,8 @@ export default class LocalParticipant extends Participant {
1648
1686
  * @param options optionally specify a `reliable`, `topic` and `destination`
1649
1687
  */
1650
1688
  async publishData(data: Uint8Array, options: DataPublishOptions = {}): Promise<void> {
1651
- const kind = options.reliable ? DataPacket_Kind.RELIABLE : DataPacket_Kind.LOSSY;
1689
+ const kind = options.reliable ? DataChannelKind.RELIABLE : DataChannelKind.LOSSY;
1690
+ const dataPacketKind = options.reliable ? DataPacket_Kind.RELIABLE : DataPacket_Kind.LOSSY;
1652
1691
  const destinationIdentities = options.destinationIdentities;
1653
1692
  const topic = options.topic;
1654
1693
 
@@ -1660,7 +1699,7 @@ export default class LocalParticipant extends Participant {
1660
1699
  });
1661
1700
 
1662
1701
  const packet = new DataPacket({
1663
- kind: kind,
1702
+ kind: dataPacketKind,
1664
1703
  value: {
1665
1704
  case: 'user',
1666
1705
  value: userPacket,
@@ -1688,7 +1727,7 @@ export default class LocalParticipant extends Participant {
1688
1727
  },
1689
1728
  });
1690
1729
 
1691
- await this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
1730
+ await this.engine.sendDataPacket(packet, DataChannelKind.RELIABLE);
1692
1731
  }
1693
1732
 
1694
1733
  /** @deprecated Consider migrating to {@link sendText} */
@@ -1708,7 +1747,7 @@ export default class LocalParticipant extends Participant {
1708
1747
  }),
1709
1748
  },
1710
1749
  });
1711
- await this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
1750
+ await this.engine.sendDataPacket(packet, DataChannelKind.RELIABLE);
1712
1751
 
1713
1752
  this.emit(ParticipantEvent.ChatMessage, msg);
1714
1753
  return msg;
@@ -1731,7 +1770,7 @@ export default class LocalParticipant extends Participant {
1731
1770
  }),
1732
1771
  },
1733
1772
  });
1734
- await this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
1773
+ await this.engine.sendDataPacket(packet, DataChannelKind.RELIABLE);
1735
1774
  this.emit(ParticipantEvent.ChatMessage, msg);
1736
1775
  return msg;
1737
1776
  }
@@ -1946,7 +1985,7 @@ export default class LocalParticipant extends Participant {
1946
1985
  },
1947
1986
  });
1948
1987
 
1949
- await this.engine.sendDataPacket(packet, DataPacket_Kind.RELIABLE);
1988
+ await this.engine.sendDataPacket(packet, DataChannelKind.RELIABLE);
1950
1989
  }
1951
1990
 
1952
1991
  /** @internal */
@@ -2235,4 +2274,16 @@ export default class LocalParticipant extends Participant {
2235
2274
  await sleep(20);
2236
2275
  }
2237
2276
  }
2277
+
2278
+ /** Publishes a data track.
2279
+ *
2280
+ * Returns the published data track if successful. Use {@link LocalDataTrack#tryPush}
2281
+ * to send data frames on the track.
2282
+ */
2283
+ async publishDataTrack(options: DataTrackOptions): Promise<LocalDataTrack> {
2284
+ const track = new LocalDataTrack(options, this.roomOutgoingDataTrackManager);
2285
+ await track.publish();
2286
+
2287
+ return track;
2288
+ }
2238
2289
  }
@@ -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
@@ -775,3 +775,7 @@ export function extractMaxAgeFromRequestHeaders(headers: Headers): number | unde
775
775
  }
776
776
  return undefined;
777
777
  }
778
+
779
+ export function isCompressionStreamSupported() {
780
+ return typeof CompressionStream !== 'undefined';
781
+ }
@@ -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
+ }
@@ -1,12 +0,0 @@
1
- export type EncryptedPayload = {
2
- payload: Uint8Array;
3
- iv: Uint8Array;
4
- keyIndex: number;
5
- };
6
- export type EncryptionProvider = {
7
- encrypt(payload: Uint8Array): EncryptedPayload;
8
- };
9
- export type DecryptionProvider = {
10
- decrypt(payload: EncryptedPayload, senderIdentity: string): Uint8Array;
11
- };
12
- //# sourceMappingURL=e2ee.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"e2ee.d.ts","sourceRoot":"","sources":["../../../../src/room/data-track/e2ee.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,UAAU,CAAC;IACpB,EAAE,EAAE,UAAU,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAE/B,OAAO,CAAC,OAAO,EAAE,UAAU,GAAG,gBAAgB,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAE/B,OAAO,CAAC,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,GAAG,UAAU,CAAC;CACxE,CAAC"}
@@ -1,12 +0,0 @@
1
- export type EncryptedPayload = {
2
- payload: Uint8Array;
3
- iv: Uint8Array;
4
- keyIndex: number;
5
- };
6
- export type EncryptionProvider = {
7
- encrypt(payload: Uint8Array): EncryptedPayload;
8
- };
9
- export type DecryptionProvider = {
10
- decrypt(payload: EncryptedPayload, senderIdentity: string): Uint8Array;
11
- };
12
- //# sourceMappingURL=e2ee.d.ts.map
@@ -1,15 +0,0 @@
1
- export type EncryptedPayload = {
2
- payload: Uint8Array;
3
- iv: Uint8Array; // NOTE: should be 12 bytes long
4
- keyIndex: number;
5
- };
6
-
7
- export type EncryptionProvider = {
8
- // FIXME: add in explicit `Throws<..., EncryptionError>`?
9
- encrypt(payload: Uint8Array): EncryptedPayload;
10
- };
11
-
12
- export type DecryptionProvider = {
13
- // FIXME: add in explicit `Throws<..., DecryptionError>`?
14
- decrypt(payload: EncryptedPayload, senderIdentity: string): Uint8Array;
15
- };