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.
Files changed (145) 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 +8026 -5883
  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/connectionHelper/ConnectionCheck.d.ts +1 -1
  12. package/dist/src/connectionHelper/ConnectionCheck.d.ts.map +1 -1
  13. package/dist/src/e2ee/constants.d.ts.map +1 -1
  14. package/dist/src/e2ee/types.d.ts +6 -0
  15. package/dist/src/e2ee/types.d.ts.map +1 -1
  16. package/dist/src/e2ee/utils.d.ts +2 -1
  17. package/dist/src/e2ee/utils.d.ts.map +1 -1
  18. package/dist/src/e2ee/worker/DataCryptor.d.ts.map +1 -1
  19. package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
  20. package/dist/src/index.d.ts +6 -4
  21. package/dist/src/index.d.ts.map +1 -1
  22. package/dist/src/room/PCTransport.d.ts +5 -0
  23. package/dist/src/room/PCTransport.d.ts.map +1 -1
  24. package/dist/src/room/PCTransportManager.d.ts +1 -1
  25. package/dist/src/room/PCTransportManager.d.ts.map +1 -1
  26. package/dist/src/room/RTCEngine.d.ts +28 -11
  27. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  28. package/dist/src/room/Room.d.ts +14 -3
  29. package/dist/src/room/Room.d.ts.map +1 -1
  30. package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts +5 -1
  31. package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts.map +1 -1
  32. package/dist/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts.map +1 -1
  33. package/dist/src/room/data-track/LocalDataTrack.d.ts +28 -5
  34. package/dist/src/room/data-track/LocalDataTrack.d.ts.map +1 -1
  35. package/dist/src/room/data-track/RemoteDataTrack.d.ts +5 -5
  36. package/dist/src/room/data-track/RemoteDataTrack.d.ts.map +1 -1
  37. package/dist/src/room/data-track/depacketizer.d.ts +4 -4
  38. package/dist/src/room/data-track/depacketizer.d.ts.map +1 -1
  39. package/dist/src/room/data-track/frame.d.ts +14 -0
  40. package/dist/src/room/data-track/frame.d.ts.map +1 -1
  41. package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts +19 -11
  42. package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts.map +1 -1
  43. package/dist/src/room/data-track/incoming/pipeline.d.ts +6 -5
  44. package/dist/src/room/data-track/incoming/pipeline.d.ts.map +1 -1
  45. package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +57 -23
  46. package/dist/src/room/data-track/outgoing/OutgoingDataTrackManager.d.ts.map +1 -1
  47. package/dist/src/room/data-track/outgoing/errors.d.ts +16 -6
  48. package/dist/src/room/data-track/outgoing/errors.d.ts.map +1 -1
  49. package/dist/src/room/data-track/outgoing/pipeline.d.ts +7 -6
  50. package/dist/src/room/data-track/outgoing/pipeline.d.ts.map +1 -1
  51. package/dist/src/room/data-track/outgoing/types.d.ts +14 -4
  52. package/dist/src/room/data-track/outgoing/types.d.ts.map +1 -1
  53. package/dist/src/room/data-track/packet/extensions.d.ts.map +1 -1
  54. package/dist/src/room/data-track/packetizer.d.ts +4 -4
  55. package/dist/src/room/data-track/packetizer.d.ts.map +1 -1
  56. package/dist/src/room/data-track/track-interfaces.d.ts +1 -1
  57. package/dist/src/room/data-track/track-interfaces.d.ts.map +1 -1
  58. package/dist/src/room/data-track/types.d.ts +6 -1
  59. package/dist/src/room/data-track/types.d.ts.map +1 -1
  60. package/dist/src/room/events.d.ts +24 -3
  61. package/dist/src/room/events.d.ts.map +1 -1
  62. package/dist/src/room/participant/LocalParticipant.d.ts +12 -1
  63. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  64. package/dist/src/room/participant/RemoteParticipant.d.ts +13 -0
  65. package/dist/src/room/participant/RemoteParticipant.d.ts.map +1 -1
  66. package/dist/src/room/utils.d.ts +1 -0
  67. package/dist/src/room/utils.d.ts.map +1 -1
  68. package/dist/src/utils/deferrable-map.d.ts +32 -0
  69. package/dist/src/utils/deferrable-map.d.ts.map +1 -0
  70. package/dist/src/utils/serializer.d.ts +48 -0
  71. package/dist/src/utils/serializer.d.ts.map +1 -0
  72. package/dist/ts4.2/api/SignalClient.d.ts +12 -4
  73. package/dist/ts4.2/connectionHelper/ConnectionCheck.d.ts +2 -1
  74. package/dist/ts4.2/e2ee/types.d.ts +6 -0
  75. package/dist/ts4.2/e2ee/utils.d.ts +2 -1
  76. package/dist/ts4.2/index.d.ts +7 -4
  77. package/dist/ts4.2/room/PCTransport.d.ts +5 -0
  78. package/dist/ts4.2/room/PCTransportManager.d.ts +1 -1
  79. package/dist/ts4.2/room/RTCEngine.d.ts +28 -11
  80. package/dist/ts4.2/room/Room.d.ts +14 -3
  81. package/dist/ts4.2/room/data-stream/incoming/IncomingDataStreamManager.d.ts +5 -1
  82. package/dist/ts4.2/room/data-track/LocalDataTrack.d.ts +27 -4
  83. package/dist/ts4.2/room/data-track/RemoteDataTrack.d.ts +4 -4
  84. package/dist/ts4.2/room/data-track/depacketizer.d.ts +4 -4
  85. package/dist/ts4.2/room/data-track/frame.d.ts +14 -0
  86. package/dist/ts4.2/room/data-track/incoming/IncomingDataTrackManager.d.ts +21 -10
  87. package/dist/ts4.2/room/data-track/incoming/pipeline.d.ts +6 -5
  88. package/dist/ts4.2/room/data-track/outgoing/OutgoingDataTrackManager.d.ts +57 -23
  89. package/dist/ts4.2/room/data-track/outgoing/errors.d.ts +16 -6
  90. package/dist/ts4.2/room/data-track/outgoing/pipeline.d.ts +7 -6
  91. package/dist/ts4.2/room/data-track/outgoing/types.d.ts +14 -4
  92. package/dist/ts4.2/room/data-track/packetizer.d.ts +4 -4
  93. package/dist/ts4.2/room/data-track/track-interfaces.d.ts +1 -1
  94. package/dist/ts4.2/room/data-track/types.d.ts +6 -1
  95. package/dist/ts4.2/room/events.d.ts +24 -3
  96. package/dist/ts4.2/room/participant/LocalParticipant.d.ts +12 -1
  97. package/dist/ts4.2/room/participant/RemoteParticipant.d.ts +13 -0
  98. package/dist/ts4.2/room/utils.d.ts +1 -0
  99. package/dist/ts4.2/utils/deferrable-map.d.ts +32 -0
  100. package/dist/ts4.2/utils/serializer.d.ts +48 -0
  101. package/package.json +1 -1
  102. package/src/api/SignalClient.test.ts +9 -4
  103. package/src/api/SignalClient.ts +116 -9
  104. package/src/connectionHelper/ConnectionCheck.ts +1 -1
  105. package/src/e2ee/constants.ts +1 -0
  106. package/src/e2ee/types.ts +6 -0
  107. package/src/e2ee/utils.ts +4 -3
  108. package/src/e2ee/worker/DataCryptor.ts +1 -4
  109. package/src/e2ee/worker/FrameCryptor.ts +1 -4
  110. package/src/e2ee/worker/ParticipantKeyHandler.ts +1 -1
  111. package/src/index.ts +13 -4
  112. package/src/room/PCTransport.ts +41 -1
  113. package/src/room/PCTransportManager.ts +1 -1
  114. package/src/room/RTCEngine.ts +312 -125
  115. package/src/room/Room.ts +168 -35
  116. package/src/room/data-stream/incoming/IncomingDataStreamManager.ts +26 -2
  117. package/src/room/data-stream/outgoing/OutgoingDataStreamManager.ts +7 -7
  118. package/src/room/data-track/LocalDataTrack.ts +83 -10
  119. package/src/room/data-track/RemoteDataTrack.ts +7 -9
  120. package/src/room/data-track/depacketizer.ts +21 -12
  121. package/src/room/data-track/frame.ts +28 -2
  122. package/src/room/data-track/incoming/IncomingDataTrackManager.test.ts +58 -73
  123. package/src/room/data-track/incoming/IncomingDataTrackManager.ts +139 -80
  124. package/src/room/data-track/incoming/pipeline.ts +29 -24
  125. package/src/room/data-track/outgoing/OutgoingDataTrackManager.test.ts +225 -32
  126. package/src/room/data-track/outgoing/OutgoingDataTrackManager.ts +150 -75
  127. package/src/room/data-track/outgoing/errors.ts +36 -7
  128. package/src/room/data-track/outgoing/pipeline.ts +23 -17
  129. package/src/room/data-track/outgoing/types.ts +12 -3
  130. package/src/room/data-track/packet/extensions.ts +17 -22
  131. package/src/room/data-track/packet/index.test.ts +22 -33
  132. package/src/room/data-track/packetizer.test.ts +2 -2
  133. package/src/room/data-track/packetizer.ts +4 -4
  134. package/src/room/data-track/track-interfaces.ts +1 -1
  135. package/src/room/data-track/types.ts +21 -1
  136. package/src/room/events.ts +26 -1
  137. package/src/room/participant/LocalParticipant.ts +74 -8
  138. package/src/room/participant/RemoteParticipant.ts +25 -0
  139. package/src/room/utils.ts +4 -0
  140. package/src/utils/deferrable-map.ts +109 -0
  141. package/src/utils/serializer.ts +72 -0
  142. package/dist/src/room/data-track/e2ee.d.ts +0 -12
  143. package/dist/src/room/data-track/e2ee.d.ts.map +0 -1
  144. package/dist/ts4.2/room/data-track/e2ee.d.ts +0 -12
  145. package/src/room/data-track/e2ee.ts +0 -15
@@ -1,7 +1,7 @@
1
1
  import { type Throws } from '@livekit/throws-transformer/throws';
2
2
  import { LoggerNames, getLogger } from '../../logger';
3
3
  import { LivekitReasonedError } from '../errors';
4
- import { type DataTrackFrame } from './frame';
4
+ import { type DataTrackFrameInternal } from './frame';
5
5
  import { DataTrackPacket, FrameMarker } from './packet';
6
6
  import { DataTrackExtensions } from './packet/extensions';
7
7
  import { U16_MAX_SIZE, WrapAroundUnsignedInt } from './utils';
@@ -38,9 +38,9 @@ export class DataTrackDepacketizerDropError<
38
38
  this.frameNumber = frameNumber;
39
39
  }
40
40
 
41
- static interrupted(frameNumber: number) {
41
+ static interrupted(frameNumber: number, newFrameNumber: number) {
42
42
  return new DataTrackDepacketizerDropError(
43
- 'Interrupted by the start of a new frame',
43
+ `Interrupted by the start of a new frame ${newFrameNumber}`,
44
44
  DataTrackDepacketizerDropReason.Interrupted,
45
45
  frameNumber,
46
46
  );
@@ -94,12 +94,12 @@ export default class DataTrackDepacketizer {
94
94
  /** Should be repeatedly called with received {@link DataTrackPacket}s - intermediate calls
95
95
  * aggregate the packet's state internally, and return null.
96
96
  *
97
- * Once this method is called with the final packet to form a frame, a new {@link DataTrackFrame}
97
+ * Once this method is called with the final packet to form a frame, a new {@link DataTrackFrameInternal}
98
98
  * is returned.*/
99
99
  push(
100
100
  packet: DataTrackPacket,
101
101
  options?: PushOptions,
102
- ): Throws<DataTrackFrame | null, DataTrackDepacketizerDropError> {
102
+ ): Throws<DataTrackFrameInternal | null, DataTrackDepacketizerDropError> {
103
103
  switch (packet.header.marker) {
104
104
  case FrameMarker.Single:
105
105
  return this.frameFromSingle(packet, options);
@@ -119,7 +119,7 @@ export default class DataTrackDepacketizer {
119
119
  packet: DataTrackPacket,
120
120
  options?: PushOptions,
121
121
  ): Throws<
122
- DataTrackFrame | null,
122
+ DataTrackFrameInternal | null,
123
123
  DataTrackDepacketizerDropError<DataTrackDepacketizerDropReason.Interrupted>
124
124
  > {
125
125
  if (packet.header.marker !== FrameMarker.Single) {
@@ -133,7 +133,10 @@ export default class DataTrackDepacketizer {
133
133
  if (options?.errorOnPartialFrames) {
134
134
  const frameNumber = this.partial.frameNumber;
135
135
  this.reset();
136
- throw DataTrackDepacketizerDropError.interrupted(frameNumber);
136
+ throw DataTrackDepacketizerDropError.interrupted(
137
+ frameNumber,
138
+ packet.header.frameNumber.value,
139
+ );
137
140
  } else {
138
141
  log.warn(
139
142
  `Data track frame ${this.partial.frameNumber} was interrupted by the start of a new frame, dropping.`,
@@ -161,10 +164,13 @@ export default class DataTrackDepacketizer {
161
164
  if (options?.errorOnPartialFrames) {
162
165
  const frameNumber = this.partial.frameNumber;
163
166
  this.reset();
164
- throw DataTrackDepacketizerDropError.interrupted(frameNumber);
167
+ throw DataTrackDepacketizerDropError.interrupted(
168
+ frameNumber,
169
+ packet.header.frameNumber.value,
170
+ );
165
171
  } else {
166
172
  log.warn(
167
- `Data track frame ${this.partial.frameNumber} was interrupted by the start of a new frame, dropping.`,
173
+ `Data track frame ${this.partial.frameNumber} was interrupted by the start of a new frame ${packet.header.frameNumber.value}, dropping.`,
168
174
  );
169
175
  }
170
176
  }
@@ -185,7 +191,7 @@ export default class DataTrackDepacketizer {
185
191
  /** Push to the existing partial frame. */
186
192
  private pushToPartial(
187
193
  packet: DataTrackPacket,
188
- ): Throws<DataTrackFrame | null, DataTrackDepacketizerDropError> {
194
+ ): Throws<DataTrackFrameInternal | null, DataTrackDepacketizerDropError> {
189
195
  if (packet.header.marker !== FrameMarker.Inter && packet.header.marker !== FrameMarker.Final) {
190
196
  // @throws-transformer ignore - this should be treated as a "panic" and not be caught
191
197
  throw new Error(
@@ -201,7 +207,10 @@ export default class DataTrackDepacketizer {
201
207
  if (packet.header.frameNumber.value !== this.partial.frameNumber) {
202
208
  const frameNumber = this.partial.frameNumber;
203
209
  this.reset();
204
- throw DataTrackDepacketizerDropError.interrupted(frameNumber);
210
+ throw DataTrackDepacketizerDropError.interrupted(
211
+ frameNumber,
212
+ packet.header.frameNumber.value,
213
+ );
205
214
  }
206
215
 
207
216
  // NOTE: this check will block reprocessing packets with duplicate sequence values if the
@@ -234,7 +243,7 @@ export default class DataTrackDepacketizer {
234
243
  partial: PartialFrame,
235
244
  endSequence: number,
236
245
  ): Throws<
237
- DataTrackFrame,
246
+ DataTrackFrameInternal,
238
247
  DataTrackDepacketizerDropError<DataTrackDepacketizerDropReason.Incomplete>
239
248
  > {
240
249
  const received = partial.payloads.size;
@@ -1,8 +1,34 @@
1
- import { DataTrackExtensions } from './packet/extensions';
2
- import DataTrackPacketizer from './packetizer';
1
+ import { DataTrackExtensions, DataTrackUserTimestampExtension } from './packet/extensions';
3
2
 
4
3
  /** A pair of payload bytes and packet extensions which can be fed into a {@link DataTrackPacketizer}. */
5
4
  export type DataTrackFrame = {
5
+ payload: Uint8Array;
6
+ userTimestamp?: bigint;
7
+ };
8
+
9
+ /** An internal representation o data track frame which contains all SFU metadata. */
10
+ export type DataTrackFrameInternal = {
6
11
  payload: Uint8Array;
7
12
  extensions: DataTrackExtensions;
8
13
  };
14
+
15
+ export const DataTrackFrameInternal = {
16
+ from(frame: DataTrackFrame) {
17
+ return {
18
+ payload: frame.payload,
19
+ extensions: new DataTrackExtensions({
20
+ userTimestamp: frame.userTimestamp
21
+ ? new DataTrackUserTimestampExtension(frame.userTimestamp)
22
+ : undefined,
23
+ }),
24
+ };
25
+ },
26
+ /** Converts from a DataTrackFrameInternal -> DataTrackFrame. Some internal information is
27
+ * discarded like e2ee encrption extension data. */
28
+ lossyIntoFrame(frame: DataTrackFrameInternal): DataTrackFrame {
29
+ return {
30
+ payload: frame.payload,
31
+ userTimestamp: frame.extensions.userTimestamp?.timestamp,
32
+ };
33
+ },
34
+ };
@@ -1,43 +1,25 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
2
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
3
  import { subscribeToEvents } from '../../../utils/subscribeToEvents';
4
- import { DecryptionProvider, EncryptedPayload } from '../e2ee';
5
- import { DataTrackFrame } from '../frame';
4
+ import { type DataTrackFrame } from '../frame';
6
5
  import { DataTrackHandle, DataTrackHandleAllocator } from '../handle';
6
+ import { PrefixingEncryptionProvider } from '../outgoing/OutgoingDataTrackManager.test';
7
7
  import { DataTrackPacket, DataTrackPacketHeader, FrameMarker } from '../packet';
8
8
  import { DataTrackE2eeExtension, DataTrackExtensions } from '../packet/extensions';
9
9
  import { DataTrackTimestamp, WrapAroundUnsignedInt } from '../utils';
10
10
  import IncomingDataTrackManager, {
11
- DataTrackIncomingManagerCallbacks,
11
+ type DataTrackIncomingManagerCallbacks,
12
12
  } from './IncomingDataTrackManager';
13
13
  import { DataTrackSubscribeError } from './errors';
14
14
 
15
- /** A fake "decryption" provider used for test purposes. Assumes the payload is prefixed with
16
- * 0xdeafbeef, which is stripped off. */
17
- const PrefixingDecryptionProvider: DecryptionProvider = {
18
- decrypt(p: EncryptedPayload, _senderIdentity: string) {
19
- if (
20
- p.payload[0] !== 0xde ||
21
- p.payload[1] !== 0xad ||
22
- p.payload[2] !== 0xbe ||
23
- p.payload[3] !== 0xef
24
- ) {
25
- throw new Error(
26
- `PrefixingDecryptionProvider: first four bytes of payload were not 0xdeadbeef, found ${p.payload.slice(0, 4)}`,
27
- );
28
- }
29
- return p.payload.slice(4);
30
- },
31
- };
32
-
33
15
  describe('DataTrackIncomingManager', () => {
34
16
  describe('Track publication', () => {
35
17
  it('should test track publication additions / removals', async () => {
36
18
  const manager = new IncomingDataTrackManager();
37
19
  const managerEvents = subscribeToEvents<DataTrackIncomingManagerCallbacks>(manager, [
38
20
  'sfuUpdateSubscription',
39
- 'trackAvailable',
40
- 'trackUnavailable',
21
+ 'trackPublished',
22
+ 'trackUnpublished',
41
23
  ]);
42
24
 
43
25
  // 1. Add a track, make sure the track available event was sent
@@ -57,11 +39,11 @@ describe('DataTrackIncomingManager', () => {
57
39
  ]),
58
40
  );
59
41
 
60
- const trackAvailableEvent = await managerEvents.waitFor('trackAvailable');
61
- expect(trackAvailableEvent.track.info.sid).toStrictEqual('sid1');
62
- expect(trackAvailableEvent.track.info.pubHandle).toStrictEqual(DataTrackHandle.fromNumber(5));
63
- expect(trackAvailableEvent.track.info.name).toStrictEqual('test');
64
- expect(trackAvailableEvent.track.info.usesE2ee).toStrictEqual(false);
42
+ const trackPublishedEvent = await managerEvents.waitFor('trackPublished');
43
+ expect(trackPublishedEvent.track.info.sid).toStrictEqual('sid1');
44
+ expect(trackPublishedEvent.track.info.pubHandle).toStrictEqual(DataTrackHandle.fromNumber(5));
45
+ expect(trackPublishedEvent.track.info.name).toStrictEqual('test');
46
+ expect(trackPublishedEvent.track.info.usesE2ee).toStrictEqual(false);
65
47
 
66
48
  // 2. Check to make sure the publication has been noted in internal state
67
49
  expect((await manager.queryPublications()).map((p) => p.pubHandle)).to.deep.equal([
@@ -72,9 +54,9 @@ describe('DataTrackIncomingManager', () => {
72
54
  await manager.receiveSfuPublicationUpdates(new Map([['identity1', []]]));
73
55
  expect(await manager.queryPublications()).to.deep.equal([]);
74
56
 
75
- const trackUnavailableEvent = await managerEvents.waitFor('trackUnavailable');
76
- expect(trackUnavailableEvent.sid).toStrictEqual('sid1');
77
- expect(trackUnavailableEvent.publisherIdentity).toStrictEqual('identity1');
57
+ const trackUnpublishedEvent = await managerEvents.waitFor('trackUnpublished');
58
+ expect(trackUnpublishedEvent.sid).toStrictEqual('sid1');
59
+ expect(trackUnpublishedEvent.publisherIdentity).toStrictEqual('identity1');
78
60
  });
79
61
 
80
62
  it('should process sfu publication updates idempotently', async () => {
@@ -111,7 +93,7 @@ describe('DataTrackIncomingManager', () => {
111
93
  const manager = new IncomingDataTrackManager();
112
94
  const managerEvents = subscribeToEvents<DataTrackIncomingManagerCallbacks>(manager, [
113
95
  'sfuUpdateSubscription',
114
- 'trackAvailable',
96
+ 'trackPublished',
115
97
  ]);
116
98
 
117
99
  const senderIdentity = 'identity';
@@ -122,10 +104,11 @@ describe('DataTrackIncomingManager', () => {
122
104
  await manager.receiveSfuPublicationUpdates(
123
105
  new Map([[senderIdentity, [{ sid, pubHandle: handle, name: 'test', usesE2ee: false }]]]),
124
106
  );
125
- await managerEvents.waitFor('trackAvailable');
107
+ await managerEvents.waitFor('trackPublished');
126
108
 
127
- // 2. Subscribe to a data track
128
- const subscribeRequestPromise = manager.subscribeRequest(sid);
109
+ // 2. Create a subscription readable stream (SFU subscription starts lazily in the background)
110
+ const [stream, sfuSubscriptionComplete] = manager.openSubscriptionStream(sid);
111
+ const reader = stream.getReader();
129
112
 
130
113
  // 3. This subscribe request should be sent along to the SFU
131
114
  const sfuUpdateSubscriptionEvent = await managerEvents.waitFor('sfuUpdateSubscription');
@@ -136,9 +119,8 @@ describe('DataTrackIncomingManager', () => {
136
119
  // the subscription
137
120
  manager.receivedSfuSubscriberHandles(new Map([[handle, sid]]));
138
121
 
139
- // 5. Make sure that the subscription promise resolves.
140
- const readableStream = await subscribeRequestPromise;
141
- const reader = readableStream.getReader();
122
+ // 5. Wait for the subscription to be fully established
123
+ await sfuSubscriptionComplete;
142
124
 
143
125
  // 6. Simulate receiving a packet
144
126
  manager.packetReceived(
@@ -163,11 +145,11 @@ describe('DataTrackIncomingManager', () => {
163
145
 
164
146
  it('should test data track subscribing with end to end encryption (ok case)', async () => {
165
147
  const manager = new IncomingDataTrackManager({
166
- decryptionProvider: PrefixingDecryptionProvider,
148
+ e2eeManager: new PrefixingEncryptionProvider(),
167
149
  });
168
150
  const managerEvents = subscribeToEvents<DataTrackIncomingManagerCallbacks>(manager, [
169
151
  'sfuUpdateSubscription',
170
- 'trackAvailable',
152
+ 'trackPublished',
171
153
  ]);
172
154
 
173
155
  const senderIdentity = 'identity';
@@ -178,10 +160,11 @@ describe('DataTrackIncomingManager', () => {
178
160
  await manager.receiveSfuPublicationUpdates(
179
161
  new Map([[senderIdentity, [{ sid, pubHandle: handle, name: 'test', usesE2ee: true }]]]),
180
162
  );
181
- await managerEvents.waitFor('trackAvailable');
163
+ await managerEvents.waitFor('trackPublished');
182
164
 
183
- // 2. Subscribe to a data track
184
- const subscribeRequestPromise = manager.subscribeRequest(sid);
165
+ // 2. Create a subscription readable stream
166
+ const [stream, sfuSubscriptionComplete] = manager.openSubscriptionStream(sid);
167
+ const reader = stream.getReader();
185
168
 
186
169
  // 3. This subscribe request should be sent along to the SFU
187
170
  const sfuUpdateSubscriptionEvent = await managerEvents.waitFor('sfuUpdateSubscription');
@@ -192,9 +175,8 @@ describe('DataTrackIncomingManager', () => {
192
175
  // the subscription
193
176
  manager.receivedSfuSubscriberHandles(new Map([[handle, sid]]));
194
177
 
195
- // 5. Make sure that the subscription promise resolves.
196
- const readableStream = await subscribeRequestPromise;
197
- const reader = readableStream.getReader();
178
+ // 5. Wait for the subscription to be fully established
179
+ await sfuSubscriptionComplete;
198
180
 
199
181
  // 6. Simulate receiving a (fake) encrypted packet
200
182
  manager.packetReceived(
@@ -228,7 +210,7 @@ describe('DataTrackIncomingManager', () => {
228
210
  const manager = new IncomingDataTrackManager();
229
211
  const managerEvents = subscribeToEvents<DataTrackIncomingManagerCallbacks>(manager, [
230
212
  'sfuUpdateSubscription',
231
- 'trackAvailable',
213
+ 'trackPublished',
232
214
  ]);
233
215
 
234
216
  const senderIdentity = 'identity';
@@ -241,13 +223,14 @@ describe('DataTrackIncomingManager', () => {
241
223
  await manager.receiveSfuPublicationUpdates(
242
224
  new Map([[senderIdentity, [{ sid, pubHandle, name: 'test', usesE2ee: false }]]]),
243
225
  );
244
- await managerEvents.waitFor('trackAvailable');
226
+ await managerEvents.waitFor('trackPublished');
245
227
 
246
228
  // 2. Set up lots of subscribers
247
229
  const readers: Array<ReadableStreamDefaultReader<DataTrackFrame>> = [];
248
230
  for (let index = 0; index < 8; index += 1) {
249
- // Subscribe to a data track
250
- const subscribeRequestPromise = manager.subscribeRequest(sid);
231
+ // Create a subscription readable stream
232
+ const [stream, sfuSubscriptionComplete] = manager.openSubscriptionStream(sid);
233
+ readers.push(stream.getReader());
251
234
 
252
235
  // Make sure that the sfu interactions ONLY happen for the first subscription opened.
253
236
  if (index === 0) {
@@ -262,10 +245,8 @@ describe('DataTrackIncomingManager', () => {
262
245
  );
263
246
  }
264
247
 
265
- // 5. Make sure that the subscription promise resolves.
266
- const readableStream = await subscribeRequestPromise;
267
- const reader = readableStream.getReader();
268
- readers.push(reader);
248
+ // 5. Wait for the subscription to be fully established
249
+ await sfuSubscriptionComplete;
269
250
  }
270
251
 
271
252
  // 6. Simulate receiving a packet
@@ -302,7 +283,7 @@ describe('DataTrackIncomingManager', () => {
302
283
  const manager = new IncomingDataTrackManager();
303
284
  const managerEvents = subscribeToEvents<DataTrackIncomingManagerCallbacks>(manager, [
304
285
  'sfuUpdateSubscription',
305
- 'trackAvailable',
286
+ 'trackPublished',
306
287
  ]);
307
288
 
308
289
  const sid = 'data track sid';
@@ -316,7 +297,7 @@ describe('DataTrackIncomingManager', () => {
316
297
  ],
317
298
  ]),
318
299
  );
319
- await managerEvents.waitFor('trackAvailable');
300
+ await managerEvents.waitFor('trackPublished');
320
301
 
321
302
  // 2. Subscribe to a data track
322
303
  const controller = new AbortController();
@@ -340,7 +321,7 @@ describe('DataTrackIncomingManager', () => {
340
321
  const manager = new IncomingDataTrackManager();
341
322
  const managerEvents = subscribeToEvents<DataTrackIncomingManagerCallbacks>(manager, [
342
323
  'sfuUpdateSubscription',
343
- 'trackAvailable',
324
+ 'trackPublished',
344
325
  ]);
345
326
 
346
327
  const sid = 'data track sid';
@@ -354,7 +335,7 @@ describe('DataTrackIncomingManager', () => {
354
335
  ],
355
336
  ]),
356
337
  );
357
- await managerEvents.waitFor('trackAvailable');
338
+ await managerEvents.waitFor('trackPublished');
358
339
 
359
340
  // 2. Subscribe to a data track twice
360
341
  const controllerOne = new AbortController();
@@ -415,7 +396,7 @@ describe('DataTrackIncomingManager', () => {
415
396
  const manager = new IncomingDataTrackManager();
416
397
  const managerEvents = subscribeToEvents<DataTrackIncomingManagerCallbacks>(manager, [
417
398
  'sfuUpdateSubscription',
418
- 'trackAvailable',
399
+ 'trackPublished',
419
400
  ]);
420
401
 
421
402
  const sid = 'data track sid';
@@ -429,7 +410,7 @@ describe('DataTrackIncomingManager', () => {
429
410
  ],
430
411
  ]),
431
412
  );
432
- await managerEvents.waitFor('trackAvailable');
413
+ await managerEvents.waitFor('trackPublished');
433
414
 
434
415
  // 2. Create subscription A
435
416
  const controllerA = new AbortController();
@@ -461,7 +442,7 @@ describe('DataTrackIncomingManager', () => {
461
442
  const manager = new IncomingDataTrackManager();
462
443
  const managerEvents = subscribeToEvents<DataTrackIncomingManagerCallbacks>(manager, [
463
444
  'sfuUpdateSubscription',
464
- 'trackAvailable',
445
+ 'trackPublished',
465
446
  ]);
466
447
 
467
448
  const senderIdentity = 'identity';
@@ -472,7 +453,7 @@ describe('DataTrackIncomingManager', () => {
472
453
  await manager.receiveSfuPublicationUpdates(
473
454
  new Map([[senderIdentity, [{ sid, pubHandle: handle, name: 'test', usesE2ee: false }]]]),
474
455
  );
475
- await managerEvents.waitFor('trackAvailable');
456
+ await managerEvents.waitFor('trackPublished');
476
457
 
477
458
  // 2. Begin subscribing to a data track
478
459
  const promise = manager.subscribeRequest(sid);
@@ -490,7 +471,7 @@ describe('DataTrackIncomingManager', () => {
490
471
  const manager = new IncomingDataTrackManager();
491
472
  const managerEvents = subscribeToEvents<DataTrackIncomingManagerCallbacks>(manager, [
492
473
  'sfuUpdateSubscription',
493
- 'trackAvailable',
474
+ 'trackPublished',
494
475
  ]);
495
476
 
496
477
  const senderIdentity = 'identity';
@@ -501,17 +482,18 @@ describe('DataTrackIncomingManager', () => {
501
482
  await manager.receiveSfuPublicationUpdates(
502
483
  new Map([[senderIdentity, [{ sid, pubHandle: handle, name: 'test', usesE2ee: false }]]]),
503
484
  );
504
- await managerEvents.waitFor('trackAvailable');
485
+ await managerEvents.waitFor('trackPublished');
505
486
 
506
487
  // 2. Subscribe to a data track, and send the handle back as if the SFU acknowledged it
507
- const subscribeRequestPromise = manager.subscribeRequest(sid);
488
+ const [stream, sfuSubscriptionComplete] = manager.openSubscriptionStream(sid);
489
+ const reader = stream.getReader();
508
490
  const sfuUpdateSubscriptionEvent = await managerEvents.waitFor('sfuUpdateSubscription');
509
491
  expect(sfuUpdateSubscriptionEvent.sid).toStrictEqual(sid);
510
492
  expect(sfuUpdateSubscriptionEvent.subscribe).toStrictEqual(true);
511
493
  manager.receivedSfuSubscriberHandles(new Map([[handle, sid]]));
512
494
 
513
495
  // 3. Start an active stream read for later
514
- const reader = (await subscribeRequestPromise).getReader();
496
+ await sfuSubscriptionComplete;
515
497
 
516
498
  // 4. Simulate the remote participant disconnecting
517
499
  manager.handleRemoteParticipantDisconnected(senderIdentity);
@@ -529,7 +511,7 @@ describe('DataTrackIncomingManager', () => {
529
511
  const manager = new IncomingDataTrackManager();
530
512
  const managerEvents = subscribeToEvents<DataTrackIncomingManagerCallbacks>(manager, [
531
513
  'sfuUpdateSubscription',
532
- 'trackAvailable',
514
+ 'trackPublished',
533
515
  ]);
534
516
 
535
517
  const senderIdentity = 'identity';
@@ -540,10 +522,11 @@ describe('DataTrackIncomingManager', () => {
540
522
  await manager.receiveSfuPublicationUpdates(
541
523
  new Map([[senderIdentity, [{ sid, pubHandle: handle, name: 'test', usesE2ee: false }]]]),
542
524
  );
543
- await managerEvents.waitFor('trackAvailable');
525
+ await managerEvents.waitFor('trackPublished');
544
526
 
545
- // 2. Subscribe to a data track
546
- const subscribeRequestPromise = manager.subscribeRequest(sid);
527
+ // 2. Create a subscription readable stream
528
+ const [stream, sfuSubscriptionComplete] = manager.openSubscriptionStream(sid);
529
+ const reader = stream.getReader();
547
530
 
548
531
  // 3. This subscribe request should be sent along to the SFU
549
532
  const sfuUpdateSubscriptionInitEvent = await managerEvents.waitFor('sfuUpdateSubscription');
@@ -554,9 +537,8 @@ describe('DataTrackIncomingManager', () => {
554
537
  // the subscription
555
538
  manager.receivedSfuSubscriberHandles(new Map([[handle, sid]]));
556
539
 
557
- // 5. Make sure that the subscription promise resolves.
558
- const readableStream = await subscribeRequestPromise;
559
- const reader = readableStream.getReader();
540
+ // 5. Wait for the subscription to be fully established
541
+ await sfuSubscriptionComplete;
560
542
 
561
543
  // 6. Manually cancel the readable stream
562
544
  await reader.cancel();
@@ -565,6 +547,9 @@ describe('DataTrackIncomingManager', () => {
565
547
  const sfuUpdateSubscriptionCancelEvent = await managerEvents.waitFor('sfuUpdateSubscription');
566
548
  expect(sfuUpdateSubscriptionCancelEvent.sid).toStrictEqual(sid);
567
549
  expect(sfuUpdateSubscriptionCancelEvent.subscribe).toStrictEqual(false);
550
+
551
+ // 8. Make sure the in flight stream is now complete
552
+ await expect(reader.read()).resolves.toStrictEqual({ value: undefined, done: true });
568
553
  });
569
554
  });
570
555
  });