livekit-client 2.18.9 → 2.18.10
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 +5609 -644
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +2870 -2420
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.pt.worker.js +2 -0
- package/dist/livekit-client.pt.worker.js.map +1 -0
- package/dist/livekit-client.pt.worker.mjs +5834 -0
- package/dist/livekit-client.pt.worker.mjs.map +1 -0
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/api/SignalClient.d.ts +2 -1
- package/dist/src/api/SignalClient.d.ts.map +1 -1
- package/dist/src/e2ee/E2eeManager.d.ts +8 -7
- package/dist/src/e2ee/E2eeManager.d.ts.map +1 -1
- package/dist/src/e2ee/types.d.ts +35 -8
- package/dist/src/e2ee/types.d.ts.map +1 -1
- package/dist/src/e2ee/utils.d.ts +5 -5
- package/dist/src/e2ee/utils.d.ts.map +1 -1
- package/dist/src/e2ee/worker/DataCryptor.d.ts +5 -5
- package/dist/src/e2ee/worker/DataCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts +21 -4
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/naluUtils.d.ts +1 -1
- package/dist/src/e2ee/worker/naluUtils.d.ts.map +1 -1
- package/dist/src/e2ee/worker/sifPayload.d.ts +7 -7
- package/dist/src/e2ee/worker/sifPayload.d.ts.map +1 -1
- package/dist/src/index.d.ts +4 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/options.d.ts +7 -0
- package/dist/src/options.d.ts.map +1 -1
- package/dist/src/packetTrailer/PacketTrailerManager.d.ts +49 -0
- package/dist/src/packetTrailer/PacketTrailerManager.d.ts.map +1 -0
- package/dist/src/packetTrailer/packetTrailer.d.ts +32 -0
- package/dist/src/packetTrailer/packetTrailer.d.ts.map +1 -0
- package/dist/src/packetTrailer/types.d.ts +57 -0
- package/dist/src/packetTrailer/types.d.ts.map +1 -0
- package/dist/src/packetTrailer/utils.d.ts +9 -0
- package/dist/src/packetTrailer/utils.d.ts.map +1 -0
- package/dist/src/packetTrailer/worker/packetTrailer.worker.d.ts +2 -0
- package/dist/src/packetTrailer/worker/packetTrailer.worker.d.ts.map +1 -0
- package/dist/src/room/RTCEngine.d.ts +2 -1
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +3 -1
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/data-track/RemoteDataTrack.d.ts +5 -1
- package/dist/src/room/data-track/RemoteDataTrack.d.ts.map +1 -1
- package/dist/src/room/data-track/depacketizer.d.ts +12 -4
- package/dist/src/room/data-track/depacketizer.d.ts.map +1 -1
- package/dist/src/room/data-track/frame.d.ts +3 -3
- package/dist/src/room/data-track/frame.d.ts.map +1 -1
- package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts +3 -1
- package/dist/src/room/data-track/incoming/IncomingDataTrackManager.d.ts.map +1 -1
- package/dist/src/room/data-track/incoming/pipeline.d.ts +4 -1
- package/dist/src/room/data-track/incoming/pipeline.d.ts.map +1 -1
- package/dist/src/room/data-track/outgoing/types.d.ts +2 -2
- package/dist/src/room/data-track/outgoing/types.d.ts.map +1 -1
- package/dist/src/room/data-track/packet/extensions.d.ts +4 -4
- package/dist/src/room/data-track/packet/extensions.d.ts.map +1 -1
- package/dist/src/room/data-track/packet/index.d.ts +5 -5
- package/dist/src/room/data-track/packet/index.d.ts.map +1 -1
- package/dist/src/room/data-track/packet/serializable.d.ts +1 -1
- package/dist/src/room/data-track/packet/serializable.d.ts.map +1 -1
- package/dist/src/room/data-track/types.d.ts +7 -0
- package/dist/src/room/data-track/types.d.ts.map +1 -1
- package/dist/src/room/events.d.ts +2 -2
- package/dist/src/room/participant/LocalParticipant.d.ts +3 -1
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/participant/Participant.d.ts +1 -1
- package/dist/src/room/participant/Participant.d.ts.map +1 -1
- package/dist/src/room/track/PacketTrailerExtractor.d.ts +19 -0
- package/dist/src/room/track/PacketTrailerExtractor.d.ts.map +1 -0
- package/dist/src/room/track/RemoteVideoTrack.d.ts +16 -0
- package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts +1 -1
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/track/create.d.ts.map +1 -1
- package/dist/src/room/track/options.d.ts +10 -0
- package/dist/src/room/track/options.d.ts.map +1 -1
- package/dist/src/room/track/utils.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +4 -3
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/src/test/MockMediaStreamTrack.d.ts.map +1 -1
- package/dist/src/utils/dataPacketBuffer.d.ts +1 -1
- package/dist/src/utils/dataPacketBuffer.d.ts.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/ts4.2/api/SignalClient.d.ts +2 -1
- package/dist/ts4.2/e2ee/E2eeManager.d.ts +8 -7
- package/dist/ts4.2/e2ee/types.d.ts +35 -8
- package/dist/ts4.2/e2ee/utils.d.ts +5 -5
- package/dist/ts4.2/e2ee/worker/DataCryptor.d.ts +5 -5
- package/dist/ts4.2/e2ee/worker/FrameCryptor.d.ts +21 -4
- package/dist/ts4.2/e2ee/worker/naluUtils.d.ts +1 -1
- package/dist/ts4.2/e2ee/worker/sifPayload.d.ts +7 -7
- package/dist/ts4.2/index.d.ts +5 -1
- package/dist/ts4.2/options.d.ts +7 -0
- package/dist/ts4.2/packetTrailer/PacketTrailerManager.d.ts +49 -0
- package/dist/ts4.2/packetTrailer/packetTrailer.d.ts +32 -0
- package/dist/ts4.2/packetTrailer/types.d.ts +57 -0
- package/dist/ts4.2/packetTrailer/utils.d.ts +9 -0
- package/dist/ts4.2/packetTrailer/worker/packetTrailer.worker.d.ts +2 -0
- package/dist/ts4.2/room/RTCEngine.d.ts +2 -1
- package/dist/ts4.2/room/Room.d.ts +3 -1
- package/dist/ts4.2/room/data-track/RemoteDataTrack.d.ts +5 -1
- package/dist/ts4.2/room/data-track/depacketizer.d.ts +12 -4
- package/dist/ts4.2/room/data-track/frame.d.ts +3 -3
- package/dist/ts4.2/room/data-track/incoming/IncomingDataTrackManager.d.ts +3 -1
- package/dist/ts4.2/room/data-track/incoming/pipeline.d.ts +4 -1
- package/dist/ts4.2/room/data-track/outgoing/types.d.ts +2 -2
- package/dist/ts4.2/room/data-track/packet/extensions.d.ts +4 -4
- package/dist/ts4.2/room/data-track/packet/index.d.ts +5 -5
- package/dist/ts4.2/room/data-track/packet/serializable.d.ts +1 -1
- package/dist/ts4.2/room/data-track/types.d.ts +7 -0
- package/dist/ts4.2/room/events.d.ts +2 -2
- package/dist/ts4.2/room/participant/LocalParticipant.d.ts +3 -1
- package/dist/ts4.2/room/participant/Participant.d.ts +1 -1
- package/dist/ts4.2/room/track/PacketTrailerExtractor.d.ts +19 -0
- package/dist/ts4.2/room/track/RemoteVideoTrack.d.ts +16 -0
- package/dist/ts4.2/room/track/Track.d.ts +1 -1
- package/dist/ts4.2/room/track/options.d.ts +10 -0
- package/dist/ts4.2/room/utils.d.ts +4 -3
- package/dist/ts4.2/utils/dataPacketBuffer.d.ts +1 -1
- package/dist/ts4.2/version.d.ts +1 -1
- package/package.json +24 -16
- package/src/api/SignalClient.test.ts +102 -10
- package/src/api/SignalClient.ts +4 -2
- package/src/api/WebSocketStream.test.ts +0 -1
- package/src/e2ee/E2eeManager.ts +82 -30
- package/src/e2ee/types.ts +37 -8
- package/src/e2ee/utils.ts +7 -6
- package/src/e2ee/worker/DataCryptor.ts +6 -6
- package/src/e2ee/worker/FrameCryptor.test.ts +177 -4
- package/src/e2ee/worker/FrameCryptor.ts +94 -14
- package/src/e2ee/worker/ParticipantKeyHandler.test.ts +4 -4
- package/src/e2ee/worker/e2ee.worker.ts +13 -5
- package/src/e2ee/worker/naluUtils.ts +4 -4
- package/src/e2ee/worker/sifPayload.ts +10 -8
- package/src/index.ts +7 -0
- package/src/options.ts +8 -0
- package/src/packetTrailer/PacketTrailerManager.test.ts +172 -0
- package/src/packetTrailer/PacketTrailerManager.ts +250 -0
- package/src/packetTrailer/packetTrailer.test.ts +174 -0
- package/src/packetTrailer/packetTrailer.ts +276 -0
- package/src/packetTrailer/types.ts +75 -0
- package/src/packetTrailer/utils.test.ts +105 -0
- package/src/packetTrailer/utils.ts +50 -0
- package/src/packetTrailer/worker/packetTrailer.worker.ts +155 -0
- package/src/packetTrailer/worker/tsconfig.json +14 -0
- package/src/room/BackOffStrategy.test.ts +1 -1
- package/src/room/RTCEngine.test.ts +219 -0
- package/src/room/RTCEngine.ts +86 -20
- package/src/room/Room.test.ts +62 -1
- package/src/room/Room.ts +28 -5
- package/src/room/data-track/RemoteDataTrack.ts +8 -1
- package/src/room/data-track/depacketizer.test.ts +433 -1
- package/src/room/data-track/depacketizer.ts +79 -61
- package/src/room/data-track/frame.ts +2 -2
- package/src/room/data-track/incoming/IncomingDataTrackManager.test.ts +194 -0
- package/src/room/data-track/incoming/IncomingDataTrackManager.ts +21 -1
- package/src/room/data-track/incoming/pipeline.ts +13 -2
- package/src/room/data-track/outgoing/types.ts +3 -2
- package/src/room/data-track/packet/extensions.ts +2 -2
- package/src/room/data-track/packet/index.ts +6 -6
- package/src/room/data-track/packet/serializable.ts +1 -1
- package/src/room/data-track/types.ts +8 -0
- package/src/room/events.ts +2 -2
- package/src/room/participant/LocalParticipant.test.ts +81 -0
- package/src/room/participant/LocalParticipant.ts +48 -7
- package/src/room/participant/Participant.ts +1 -1
- package/src/room/participant/publishUtils.ts +1 -1
- package/src/room/track/PacketTrailerExtractor.ts +43 -0
- package/src/room/track/RemoteVideoTrack.ts +23 -2
- package/src/room/track/Track.ts +1 -1
- package/src/room/track/create.ts +0 -4
- package/src/room/track/options.ts +11 -0
- package/src/room/track/record.ts +1 -1
- package/src/room/track/utils.ts +4 -1
- package/src/room/utils.test.ts +14 -1
- package/src/room/utils.ts +17 -3
- package/src/test/MockMediaStreamTrack.ts +0 -1
- package/src/type-polyfills/non-shared-typed-arrays.d.ts +6 -0
- package/src/utils/dataPacketBuffer.ts +1 -1
- package/src/version.ts +1 -1
|
@@ -9,14 +9,12 @@ import { U16_MAX_SIZE, WrapAroundUnsignedInt } from './utils';
|
|
|
9
9
|
const log = getLogger(LoggerNames.DataTracks);
|
|
10
10
|
|
|
11
11
|
type PartialFrame = {
|
|
12
|
-
/** Frame number from the start packet. */
|
|
13
|
-
frameNumber: number;
|
|
14
12
|
/** Sequence of the start packet. */
|
|
15
13
|
startSequence: WrapAroundUnsignedInt<typeof U16_MAX_SIZE>;
|
|
16
14
|
/** Extensions from the start packet. */
|
|
17
15
|
extensions: DataTrackExtensions;
|
|
18
16
|
/** Mapping between sequence number and packet payload. */
|
|
19
|
-
payloads: Map<number,
|
|
17
|
+
payloads: Map<number, NonSharedUint8Array>;
|
|
20
18
|
};
|
|
21
19
|
|
|
22
20
|
/** An error indicating a frame was dropped. */
|
|
@@ -80,16 +78,24 @@ export enum DataTrackDepacketizerDropReason {
|
|
|
80
78
|
}
|
|
81
79
|
|
|
82
80
|
type PushOptions = {
|
|
83
|
-
/** If true, throws
|
|
84
|
-
*
|
|
85
|
-
|
|
81
|
+
/** If true, throws `DataTrackDepacketizerDropError.interrupted` instead of logging a warning
|
|
82
|
+
* when a new frame arrives while the partials map is at capacity. */
|
|
83
|
+
throwOnInterruption: boolean;
|
|
84
|
+
|
|
85
|
+
/** Maximum number of partial frames the depacketizer will track concurrently. When a new
|
|
86
|
+
* frame arrives while the partials map is at capacity, the oldest partial is evicted (or
|
|
87
|
+
* `DataTrackDepacketizerDropError.interrupted` is thrown when `throwOnInterruption` is set).
|
|
88
|
+
* Defaults to 1. */
|
|
89
|
+
maxPartialFrames?: number;
|
|
86
90
|
};
|
|
87
91
|
|
|
88
92
|
export default class DataTrackDepacketizer {
|
|
89
93
|
/** Maximum number of packets to buffer per frame before dropping. */
|
|
90
94
|
static MAX_BUFFER_PACKETS = 128;
|
|
91
95
|
|
|
92
|
-
|
|
96
|
+
/** Partial frames currently being assembled, keyed by frame number. `Map` preserves insertion
|
|
97
|
+
* order, so the oldest entry is the first key. */
|
|
98
|
+
private partials: Map<number, PartialFrame> = new Map();
|
|
93
99
|
|
|
94
100
|
/** Should be repeatedly called with received {@link DataTrackPacket}s - intermediate calls
|
|
95
101
|
* aggregate the packet's state internally, and return null.
|
|
@@ -112,14 +118,19 @@ export default class DataTrackDepacketizer {
|
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
reset() {
|
|
115
|
-
this.
|
|
121
|
+
this.partials.clear();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private peekOldestPartialFrameNumber(): number | null {
|
|
125
|
+
const first = this.partials.keys().next();
|
|
126
|
+
return first.done ? null : first.value;
|
|
116
127
|
}
|
|
117
128
|
|
|
118
129
|
private frameFromSingle(
|
|
119
130
|
packet: DataTrackPacket,
|
|
120
131
|
options?: PushOptions,
|
|
121
132
|
): Throws<
|
|
122
|
-
DataTrackFrameInternal
|
|
133
|
+
DataTrackFrameInternal,
|
|
123
134
|
DataTrackDepacketizerDropError<DataTrackDepacketizerDropReason.Interrupted>
|
|
124
135
|
> {
|
|
125
136
|
if (packet.header.marker !== FrameMarker.Single) {
|
|
@@ -129,21 +140,30 @@ export default class DataTrackDepacketizer {
|
|
|
129
140
|
);
|
|
130
141
|
}
|
|
131
142
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
143
|
+
// A `Single` packet is a self-contained frame and doesn't reserve a partials slot, but if
|
|
144
|
+
// the partials map is at capacity, treat it as a signal that the oldest in-flight partial
|
|
145
|
+
// is stale and evict it (matches `main`'s behavior when `maxPartialFrames`
|
|
146
|
+
// defaults to 1).
|
|
147
|
+
const maxPartialFrames = options?.maxPartialFrames ?? 1;
|
|
148
|
+
if (this.partials.size >= maxPartialFrames) {
|
|
149
|
+
const oldestPartialFrameNumber = this.peekOldestPartialFrameNumber();
|
|
150
|
+
if (typeof oldestPartialFrameNumber !== 'number') {
|
|
151
|
+
// @throws-transformer ignore - this should be treated as a "panic" and not be caught
|
|
152
|
+
throw new Error(
|
|
153
|
+
`Depacketizer.frameFromSingle: no oldest frame number found, but partials.size is ${this.partials.size}.`,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
this.partials.delete(oldestPartialFrameNumber);
|
|
157
|
+
if (options?.throwOnInterruption) {
|
|
136
158
|
throw DataTrackDepacketizerDropError.interrupted(
|
|
137
|
-
|
|
159
|
+
oldestPartialFrameNumber,
|
|
138
160
|
packet.header.frameNumber.value,
|
|
139
161
|
);
|
|
140
|
-
} else {
|
|
141
|
-
log.warn(
|
|
142
|
-
`Data track frame ${this.partial.frameNumber} was interrupted by the start of a new frame, dropping.`,
|
|
143
|
-
);
|
|
144
162
|
}
|
|
163
|
+
log.warn(
|
|
164
|
+
`Data track frame ${oldestPartialFrameNumber} was interrupted by single-packet frame ${packet.header.frameNumber.value}, dropping.`,
|
|
165
|
+
);
|
|
145
166
|
}
|
|
146
|
-
this.reset();
|
|
147
167
|
|
|
148
168
|
return { payload: packet.payload, extensions: packet.header.extensions };
|
|
149
169
|
}
|
|
@@ -160,31 +180,36 @@ export default class DataTrackDepacketizer {
|
|
|
160
180
|
);
|
|
161
181
|
}
|
|
162
182
|
|
|
163
|
-
if (this.partial) {
|
|
164
|
-
if (options?.errorOnPartialFrames) {
|
|
165
|
-
const frameNumber = this.partial.frameNumber;
|
|
166
|
-
this.reset();
|
|
167
|
-
throw DataTrackDepacketizerDropError.interrupted(
|
|
168
|
-
frameNumber,
|
|
169
|
-
packet.header.frameNumber.value,
|
|
170
|
-
);
|
|
171
|
-
} else {
|
|
172
|
-
log.warn(
|
|
173
|
-
`Data track frame ${this.partial.frameNumber} was interrupted by the start of a new frame ${packet.header.frameNumber.value}, dropping.`,
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
this.reset();
|
|
178
|
-
|
|
179
183
|
const startSequence = packet.header.sequence;
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
frameNumber: packet.header.frameNumber.value,
|
|
184
|
+
const frameNumber = packet.header.frameNumber.value;
|
|
185
|
+
const partial: PartialFrame = {
|
|
183
186
|
startSequence,
|
|
184
187
|
extensions: packet.header.extensions,
|
|
185
188
|
payloads: new Map([[startSequence.value, packet.payload]]),
|
|
186
189
|
};
|
|
187
190
|
|
|
191
|
+
// Loop in case `maxPartialFrames` shrunk relative to a previous push call - evict the
|
|
192
|
+
// oldest partials until there is room for the new one. With `throwOnInterruption` set the
|
|
193
|
+
// throw inside the loop short-circuits on the first eviction, matching the single-eviction
|
|
194
|
+
// behavior callers expect when they ask to be told about interruptions.
|
|
195
|
+
const maxPartialFrames = options?.maxPartialFrames ?? 1;
|
|
196
|
+
while (this.partials.size >= maxPartialFrames) {
|
|
197
|
+
const oldestPartialFrameNumber = this.peekOldestPartialFrameNumber();
|
|
198
|
+
if (typeof oldestPartialFrameNumber !== 'number') {
|
|
199
|
+
// partials map is empty - nothing more to evict
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
this.partials.delete(oldestPartialFrameNumber);
|
|
203
|
+
|
|
204
|
+
if (options?.throwOnInterruption) {
|
|
205
|
+
throw DataTrackDepacketizerDropError.interrupted(oldestPartialFrameNumber, frameNumber);
|
|
206
|
+
}
|
|
207
|
+
log.warn(
|
|
208
|
+
`Data track partials full (max ${maxPartialFrames}), evicted oldest frame ${oldestPartialFrameNumber} to make room for new frame ${frameNumber}.`,
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
this.partials.set(frameNumber, partial);
|
|
212
|
+
|
|
188
213
|
return null;
|
|
189
214
|
}
|
|
190
215
|
|
|
@@ -199,40 +224,32 @@ export default class DataTrackDepacketizer {
|
|
|
199
224
|
);
|
|
200
225
|
}
|
|
201
226
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if (packet.header.frameNumber.value !== this.partial.frameNumber) {
|
|
208
|
-
const frameNumber = this.partial.frameNumber;
|
|
209
|
-
this.reset();
|
|
210
|
-
throw DataTrackDepacketizerDropError.interrupted(
|
|
211
|
-
frameNumber,
|
|
212
|
-
packet.header.frameNumber.value,
|
|
213
|
-
);
|
|
227
|
+
const packetFrameNumber = packet.header.frameNumber.value;
|
|
228
|
+
const matchingPartial = this.partials.get(packetFrameNumber);
|
|
229
|
+
if (!matchingPartial) {
|
|
230
|
+
this.partials.delete(packetFrameNumber);
|
|
231
|
+
throw DataTrackDepacketizerDropError.unknownFrame(packetFrameNumber);
|
|
214
232
|
}
|
|
215
233
|
|
|
216
234
|
// NOTE: this check will block reprocessing packets with duplicate sequence values if the
|
|
217
235
|
// buffer is full already, which could maybe be problematic for very large frames.
|
|
218
|
-
if (
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
throw DataTrackDepacketizerDropError.bufferFull(frameNumber);
|
|
236
|
+
if (matchingPartial.payloads.size >= DataTrackDepacketizer.MAX_BUFFER_PACKETS) {
|
|
237
|
+
this.partials.delete(packetFrameNumber);
|
|
238
|
+
throw DataTrackDepacketizerDropError.bufferFull(packetFrameNumber);
|
|
222
239
|
}
|
|
223
240
|
|
|
224
241
|
// Note: receiving a packet with a duplicate `sequence` value is something that likely won't
|
|
225
242
|
// happen in actual use, but even if it does (maybe a low level network retransmission?) the
|
|
226
243
|
// last packet with a given sequence received should always win.
|
|
227
|
-
if (
|
|
244
|
+
if (matchingPartial.payloads.has(packet.header.sequence.value)) {
|
|
228
245
|
log.warn(
|
|
229
|
-
`Data track frame ${
|
|
246
|
+
`Data track frame ${packetFrameNumber} received duplicate packet for sequence ${packet.header.sequence.value}, so replacing with newly received packet.`,
|
|
230
247
|
);
|
|
231
248
|
}
|
|
232
|
-
|
|
249
|
+
matchingPartial.payloads.set(packet.header.sequence.value, packet.payload);
|
|
233
250
|
|
|
234
251
|
if (packet.header.marker === FrameMarker.Final) {
|
|
235
|
-
return this.finalize(
|
|
252
|
+
return this.finalize(packetFrameNumber, matchingPartial, packet.header.sequence.value);
|
|
236
253
|
}
|
|
237
254
|
|
|
238
255
|
return null;
|
|
@@ -240,6 +257,7 @@ export default class DataTrackDepacketizer {
|
|
|
240
257
|
|
|
241
258
|
/** Try to reassemble the complete frame. */
|
|
242
259
|
private finalize(
|
|
260
|
+
partialFrameNumber: number,
|
|
243
261
|
partial: PartialFrame,
|
|
244
262
|
endSequence: number,
|
|
245
263
|
): Throws<
|
|
@@ -281,13 +299,13 @@ export default class DataTrackDepacketizer {
|
|
|
281
299
|
}
|
|
282
300
|
|
|
283
301
|
// The packet is done processing, reset the state so another frame can be processed next.
|
|
284
|
-
this.
|
|
302
|
+
this.partials.delete(partialFrameNumber);
|
|
285
303
|
return { payload, extensions: partial.extensions };
|
|
286
304
|
}
|
|
287
305
|
|
|
288
|
-
this.
|
|
306
|
+
this.partials.delete(partialFrameNumber);
|
|
289
307
|
throw DataTrackDepacketizerDropError.incomplete(
|
|
290
|
-
|
|
308
|
+
partialFrameNumber,
|
|
291
309
|
received,
|
|
292
310
|
endSequence - partial.startSequence.value + 1,
|
|
293
311
|
);
|
|
@@ -2,13 +2,13 @@ import { DataTrackExtensions, DataTrackUserTimestampExtension } from './packet/e
|
|
|
2
2
|
|
|
3
3
|
/** A pair of payload bytes and packet extensions which can be fed into a {@link DataTrackPacketizer}. */
|
|
4
4
|
export type DataTrackFrame = {
|
|
5
|
-
payload:
|
|
5
|
+
payload: NonSharedUint8Array;
|
|
6
6
|
userTimestamp?: bigint;
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
/** An internal representation o data track frame which contains all SFU metadata. */
|
|
10
10
|
export type DataTrackFrameInternal = {
|
|
11
|
-
payload:
|
|
11
|
+
payload: NonSharedUint8Array;
|
|
12
12
|
extensions: DataTrackExtensions;
|
|
13
13
|
};
|
|
14
14
|
|
|
@@ -936,5 +936,199 @@ describe('DataTrackIncomingManager', () => {
|
|
|
936
936
|
process.off('unhandledRejection', onUnhandled);
|
|
937
937
|
}
|
|
938
938
|
});
|
|
939
|
+
|
|
940
|
+
it('should depacketize multiple interleaved partial frames when setMaxPartialFrames is called before subscribe', async () => {
|
|
941
|
+
const manager = new IncomingDataTrackManager();
|
|
942
|
+
const managerEvents = subscribeToEvents<DataTrackIncomingManagerCallbacks>(manager, [
|
|
943
|
+
'sfuUpdateSubscription',
|
|
944
|
+
'trackPublished',
|
|
945
|
+
]);
|
|
946
|
+
|
|
947
|
+
const senderIdentity = 'identity';
|
|
948
|
+
const sid = 'data track sid';
|
|
949
|
+
const handle = DataTrackHandle.fromNumber(5);
|
|
950
|
+
|
|
951
|
+
await manager.receiveSfuPublicationUpdates(
|
|
952
|
+
new Map([[senderIdentity, [{ sid, pubHandle: handle, name: 'test', usesE2ee: false }]]]),
|
|
953
|
+
);
|
|
954
|
+
const trackPublishedEvent = await managerEvents.waitFor('trackPublished');
|
|
955
|
+
|
|
956
|
+
// Configure the track BEFORE any subscribe.
|
|
957
|
+
trackPublishedEvent.track.setPipelineOptions({ maxPartialFrames: 3 });
|
|
958
|
+
|
|
959
|
+
const [stream, sfuSubscriptionComplete] = manager.openSubscriptionStream(sid);
|
|
960
|
+
const reader = stream.getReader();
|
|
961
|
+
|
|
962
|
+
await managerEvents.waitFor('sfuUpdateSubscription');
|
|
963
|
+
manager.receivedSfuSubscriberHandles(new Map([[handle, sid]]));
|
|
964
|
+
await sfuSubscriptionComplete;
|
|
965
|
+
|
|
966
|
+
// Two interleaved partial frames: Start(1), Start(2), Final(1), Final(2). With the default
|
|
967
|
+
// maxPartialFrames=1 frame 1 would be evicted by frame 2; with maxPartialFrames=3 both
|
|
968
|
+
// frames coexist and emerge.
|
|
969
|
+
pushInterleavedTwoFramePair(manager, handle, {
|
|
970
|
+
frameOneNumber: 1,
|
|
971
|
+
frameOneStartSequence: 0,
|
|
972
|
+
frameOnePayloads: [new Uint8Array([0xa1]), new Uint8Array([0xa2])],
|
|
973
|
+
frameTwoNumber: 2,
|
|
974
|
+
frameTwoStartSequence: 100,
|
|
975
|
+
frameTwoPayloads: [new Uint8Array([0xb1]), new Uint8Array([0xb2])],
|
|
976
|
+
});
|
|
977
|
+
|
|
978
|
+
const first = await reader.read();
|
|
979
|
+
expect(first.done).toStrictEqual(false);
|
|
980
|
+
expect(first.value?.payload).toStrictEqual(new Uint8Array([0xa1, 0xa2]));
|
|
981
|
+
|
|
982
|
+
const second = await reader.read();
|
|
983
|
+
expect(second.done).toStrictEqual(false);
|
|
984
|
+
expect(second.value?.payload).toStrictEqual(new Uint8Array([0xb1, 0xb2]));
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
it('should pick up setMaxPartialFrames live on an already-active subscription', async () => {
|
|
988
|
+
const manager = new IncomingDataTrackManager();
|
|
989
|
+
const managerEvents = subscribeToEvents<DataTrackIncomingManagerCallbacks>(manager, [
|
|
990
|
+
'sfuUpdateSubscription',
|
|
991
|
+
'trackPublished',
|
|
992
|
+
]);
|
|
993
|
+
|
|
994
|
+
const senderIdentity = 'identity';
|
|
995
|
+
const sid = 'data track sid';
|
|
996
|
+
const handle = DataTrackHandle.fromNumber(5);
|
|
997
|
+
|
|
998
|
+
await manager.receiveSfuPublicationUpdates(
|
|
999
|
+
new Map([[senderIdentity, [{ sid, pubHandle: handle, name: 'test', usesE2ee: false }]]]),
|
|
1000
|
+
);
|
|
1001
|
+
const trackPublishedEvent = await managerEvents.waitFor('trackPublished');
|
|
1002
|
+
|
|
1003
|
+
const [stream, sfuSubscriptionComplete] = manager.openSubscriptionStream(sid);
|
|
1004
|
+
const reader = stream.getReader();
|
|
1005
|
+
|
|
1006
|
+
await managerEvents.waitFor('sfuUpdateSubscription');
|
|
1007
|
+
manager.receivedSfuSubscriberHandles(new Map([[handle, sid]]));
|
|
1008
|
+
await sfuSubscriptionComplete;
|
|
1009
|
+
|
|
1010
|
+
// Subscription is now active; flip the cap on the live pipeline.
|
|
1011
|
+
trackPublishedEvent.track.setPipelineOptions({ maxPartialFrames: 3 });
|
|
1012
|
+
|
|
1013
|
+
pushInterleavedTwoFramePair(manager, handle, {
|
|
1014
|
+
frameOneNumber: 1,
|
|
1015
|
+
frameOneStartSequence: 0,
|
|
1016
|
+
frameOnePayloads: [new Uint8Array([0xa1]), new Uint8Array([0xa2])],
|
|
1017
|
+
frameTwoNumber: 2,
|
|
1018
|
+
frameTwoStartSequence: 100,
|
|
1019
|
+
frameTwoPayloads: [new Uint8Array([0xb1]), new Uint8Array([0xb2])],
|
|
1020
|
+
});
|
|
1021
|
+
|
|
1022
|
+
const first = await reader.read();
|
|
1023
|
+
expect(first.value?.payload).toStrictEqual(new Uint8Array([0xa1, 0xa2]));
|
|
1024
|
+
|
|
1025
|
+
const second = await reader.read();
|
|
1026
|
+
expect(second.value?.payload).toStrictEqual(new Uint8Array([0xb1, 0xb2]));
|
|
1027
|
+
});
|
|
1028
|
+
|
|
1029
|
+
it('should drop the older partial frame by default (no setMaxPartialFrames call)', async () => {
|
|
1030
|
+
const manager = new IncomingDataTrackManager();
|
|
1031
|
+
const managerEvents = subscribeToEvents<DataTrackIncomingManagerCallbacks>(manager, [
|
|
1032
|
+
'sfuUpdateSubscription',
|
|
1033
|
+
'trackPublished',
|
|
1034
|
+
]);
|
|
1035
|
+
|
|
1036
|
+
const senderIdentity = 'identity';
|
|
1037
|
+
const sid = 'data track sid';
|
|
1038
|
+
const handle = DataTrackHandle.fromNumber(5);
|
|
1039
|
+
|
|
1040
|
+
await manager.receiveSfuPublicationUpdates(
|
|
1041
|
+
new Map([[senderIdentity, [{ sid, pubHandle: handle, name: 'test', usesE2ee: false }]]]),
|
|
1042
|
+
);
|
|
1043
|
+
await managerEvents.waitFor('trackPublished');
|
|
1044
|
+
|
|
1045
|
+
const [stream, sfuSubscriptionComplete] = manager.openSubscriptionStream(sid);
|
|
1046
|
+
const reader = stream.getReader();
|
|
1047
|
+
|
|
1048
|
+
await managerEvents.waitFor('sfuUpdateSubscription');
|
|
1049
|
+
manager.receivedSfuSubscriberHandles(new Map([[handle, sid]]));
|
|
1050
|
+
await sfuSubscriptionComplete;
|
|
1051
|
+
|
|
1052
|
+
// Default cap of 1: Start(2) evicts Start(1), so Final(1) is unknown and only frame 2
|
|
1053
|
+
// makes it through.
|
|
1054
|
+
pushInterleavedTwoFramePair(manager, handle, {
|
|
1055
|
+
frameOneNumber: 1,
|
|
1056
|
+
frameOneStartSequence: 0,
|
|
1057
|
+
frameOnePayloads: [new Uint8Array([0xa1]), new Uint8Array([0xa2])],
|
|
1058
|
+
frameTwoNumber: 2,
|
|
1059
|
+
frameTwoStartSequence: 100,
|
|
1060
|
+
frameTwoPayloads: [new Uint8Array([0xb1]), new Uint8Array([0xb2])],
|
|
1061
|
+
});
|
|
1062
|
+
|
|
1063
|
+
const onlyFrame = await reader.read();
|
|
1064
|
+
expect(onlyFrame.done).toStrictEqual(false);
|
|
1065
|
+
expect(onlyFrame.value?.payload).toStrictEqual(new Uint8Array([0xb1, 0xb2]));
|
|
1066
|
+
});
|
|
939
1067
|
});
|
|
940
1068
|
});
|
|
1069
|
+
|
|
1070
|
+
/** Pushes Start(frame1), Start(frame2), Final(frame1), Final(frame2) packets through the manager
|
|
1071
|
+
* to exercise the depacketizer's concurrent-partial-frame handling. */
|
|
1072
|
+
function pushInterleavedTwoFramePair(
|
|
1073
|
+
manager: IncomingDataTrackManager,
|
|
1074
|
+
trackHandle: DataTrackHandle,
|
|
1075
|
+
args: {
|
|
1076
|
+
frameOneNumber: number;
|
|
1077
|
+
frameOneStartSequence: number;
|
|
1078
|
+
frameOnePayloads: [Uint8Array, Uint8Array];
|
|
1079
|
+
frameTwoNumber: number;
|
|
1080
|
+
frameTwoStartSequence: number;
|
|
1081
|
+
frameTwoPayloads: [Uint8Array, Uint8Array];
|
|
1082
|
+
},
|
|
1083
|
+
) {
|
|
1084
|
+
const buildPacket = (
|
|
1085
|
+
frameNumber: number,
|
|
1086
|
+
sequence: number,
|
|
1087
|
+
marker: FrameMarker,
|
|
1088
|
+
payload: Uint8Array,
|
|
1089
|
+
) =>
|
|
1090
|
+
new DataTrackPacket(
|
|
1091
|
+
new DataTrackPacketHeader({
|
|
1092
|
+
extensions: new DataTrackExtensions(),
|
|
1093
|
+
frameNumber: WrapAroundUnsignedInt.u16(frameNumber),
|
|
1094
|
+
marker,
|
|
1095
|
+
sequence: WrapAroundUnsignedInt.u16(sequence),
|
|
1096
|
+
timestamp: DataTrackTimestamp.fromRtpTicks(0),
|
|
1097
|
+
trackHandle,
|
|
1098
|
+
}),
|
|
1099
|
+
payload,
|
|
1100
|
+
).toBinary();
|
|
1101
|
+
|
|
1102
|
+
manager.packetReceived(
|
|
1103
|
+
buildPacket(
|
|
1104
|
+
args.frameOneNumber,
|
|
1105
|
+
args.frameOneStartSequence,
|
|
1106
|
+
FrameMarker.Start,
|
|
1107
|
+
args.frameOnePayloads[0],
|
|
1108
|
+
),
|
|
1109
|
+
);
|
|
1110
|
+
manager.packetReceived(
|
|
1111
|
+
buildPacket(
|
|
1112
|
+
args.frameTwoNumber,
|
|
1113
|
+
args.frameTwoStartSequence,
|
|
1114
|
+
FrameMarker.Start,
|
|
1115
|
+
args.frameTwoPayloads[0],
|
|
1116
|
+
),
|
|
1117
|
+
);
|
|
1118
|
+
manager.packetReceived(
|
|
1119
|
+
buildPacket(
|
|
1120
|
+
args.frameOneNumber,
|
|
1121
|
+
args.frameOneStartSequence + 1,
|
|
1122
|
+
FrameMarker.Final,
|
|
1123
|
+
args.frameOnePayloads[1],
|
|
1124
|
+
),
|
|
1125
|
+
);
|
|
1126
|
+
manager.packetReceived(
|
|
1127
|
+
buildPacket(
|
|
1128
|
+
args.frameTwoNumber,
|
|
1129
|
+
args.frameTwoStartSequence + 1,
|
|
1130
|
+
FrameMarker.Final,
|
|
1131
|
+
args.frameTwoPayloads[1],
|
|
1132
|
+
),
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
@@ -13,7 +13,11 @@ import { DataTrackDepacketizerDropError } from '../depacketizer';
|
|
|
13
13
|
import { type DataTrackFrame, DataTrackFrameInternal } from '../frame';
|
|
14
14
|
import { DataTrackHandle } from '../handle';
|
|
15
15
|
import { DataTrackPacket } from '../packet';
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
type DataTrackInfo,
|
|
18
|
+
type DataTrackSid,
|
|
19
|
+
type RemoteDataTrackPipelineOptions,
|
|
20
|
+
} from '../types';
|
|
17
21
|
import { DataTrackSubscribeError } from './errors';
|
|
18
22
|
import IncomingDataTrackPipeline from './pipeline';
|
|
19
23
|
import {
|
|
@@ -65,6 +69,7 @@ type Descriptor<S extends SubscriptionState> = {
|
|
|
65
69
|
info: DataTrackInfo;
|
|
66
70
|
publisherIdentity: Participant['identity'];
|
|
67
71
|
subscription: S;
|
|
72
|
+
pipelineOptions: RemoteDataTrackPipelineOptions;
|
|
68
73
|
};
|
|
69
74
|
|
|
70
75
|
type IncomingDataTrackManagerOptions = {
|
|
@@ -113,6 +118,19 @@ export default class IncomingDataTrackManager extends (EventEmitter as new () =>
|
|
|
113
118
|
}
|
|
114
119
|
}
|
|
115
120
|
|
|
121
|
+
/** @internal */
|
|
122
|
+
setPipelineOptions(sid: DataTrackSid, options: RemoteDataTrackPipelineOptions): void {
|
|
123
|
+
const descriptor = this.descriptors.get(sid);
|
|
124
|
+
if (!descriptor) {
|
|
125
|
+
log.warn(`Unknown track ${sid}, cannot set pipeline options.`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
descriptor.pipelineOptions = options;
|
|
129
|
+
if (descriptor.subscription.type === 'active') {
|
|
130
|
+
descriptor.subscription.pipeline.setOptions(options);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
116
134
|
/** Allocates a ReadableStream which emits when a new {@link DataTrackFrame} is received from the
|
|
117
135
|
* SFU. The SFU subscription is initiated lazily when the stream is created.
|
|
118
136
|
*
|
|
@@ -473,6 +491,7 @@ export default class IncomingDataTrackManager extends (EventEmitter as new () =>
|
|
|
473
491
|
info,
|
|
474
492
|
publisherIdentity,
|
|
475
493
|
subscription: { type: 'none' },
|
|
494
|
+
pipelineOptions: {},
|
|
476
495
|
};
|
|
477
496
|
this.descriptors.set(descriptor.info.sid, descriptor);
|
|
478
497
|
|
|
@@ -530,6 +549,7 @@ export default class IncomingDataTrackManager extends (EventEmitter as new () =>
|
|
|
530
549
|
info: descriptor.info,
|
|
531
550
|
publisherIdentity: descriptor.publisherIdentity,
|
|
532
551
|
e2eeManager: this.e2eeManager,
|
|
552
|
+
pipelineOptions: descriptor.pipelineOptions,
|
|
533
553
|
});
|
|
534
554
|
|
|
535
555
|
const previousDescriptorSubscription = descriptor.subscription;
|
|
@@ -4,7 +4,7 @@ import { LoggerNames, getLogger } from '../../../logger';
|
|
|
4
4
|
import DataTrackDepacketizer, { DataTrackDepacketizerDropError } from '../depacketizer';
|
|
5
5
|
import type { DataTrackFrameInternal } from '../frame';
|
|
6
6
|
import { DataTrackPacket } from '../packet';
|
|
7
|
-
import { type DataTrackInfo } from '../types';
|
|
7
|
+
import { type DataTrackInfo, type RemoteDataTrackPipelineOptions } from '../types';
|
|
8
8
|
|
|
9
9
|
const log = getLogger(LoggerNames.DataTracks);
|
|
10
10
|
|
|
@@ -15,6 +15,7 @@ type Options = {
|
|
|
15
15
|
info: DataTrackInfo;
|
|
16
16
|
publisherIdentity: string;
|
|
17
17
|
e2eeManager: BaseE2EEManager | null;
|
|
18
|
+
pipelineOptions?: RemoteDataTrackPipelineOptions;
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
/**
|
|
@@ -27,6 +28,8 @@ export default class IncomingDataTrackPipeline {
|
|
|
27
28
|
|
|
28
29
|
private depacketizer: DataTrackDepacketizer;
|
|
29
30
|
|
|
31
|
+
private options: RemoteDataTrackPipelineOptions;
|
|
32
|
+
|
|
30
33
|
/**
|
|
31
34
|
* Creates a new pipeline with the given options.
|
|
32
35
|
*/
|
|
@@ -44,12 +47,17 @@ export default class IncomingDataTrackPipeline {
|
|
|
44
47
|
this.publisherIdentity = options.publisherIdentity;
|
|
45
48
|
this.e2eeManager = options.e2eeManager ?? null;
|
|
46
49
|
this.depacketizer = depacketizer;
|
|
50
|
+
this.options = options.pipelineOptions ?? {};
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
updateE2eeManager(e2eeManager: BaseE2EEManager | null) {
|
|
50
54
|
this.e2eeManager = e2eeManager;
|
|
51
55
|
}
|
|
52
56
|
|
|
57
|
+
setOptions(options: RemoteDataTrackPipelineOptions): void {
|
|
58
|
+
this.options = options;
|
|
59
|
+
}
|
|
60
|
+
|
|
53
61
|
async processPacket(
|
|
54
62
|
packet: DataTrackPacket,
|
|
55
63
|
): Promise<Throws<DataTrackFrameInternal | null, DataTrackDepacketizerDropError>> {
|
|
@@ -74,7 +82,10 @@ export default class IncomingDataTrackPipeline {
|
|
|
74
82
|
): Throws<DataTrackFrameInternal | null, DataTrackDepacketizerDropError> {
|
|
75
83
|
let frame: DataTrackFrameInternal | null;
|
|
76
84
|
try {
|
|
77
|
-
frame = this.depacketizer.push(packet
|
|
85
|
+
frame = this.depacketizer.push(packet, {
|
|
86
|
+
throwOnInterruption: false,
|
|
87
|
+
maxPartialFrames: this.options.maxPartialFrames,
|
|
88
|
+
});
|
|
78
89
|
} catch (err) {
|
|
79
90
|
// In a future version, use this to maintain drop statistics.
|
|
80
91
|
// FIXME: is this a good idea?
|
|
@@ -17,7 +17,8 @@ export type SfuPublishResponseResult =
|
|
|
17
17
|
| DataTrackPublishError<DataTrackPublishErrorReason.NotAllowed>
|
|
18
18
|
| DataTrackPublishError<DataTrackPublishErrorReason.DuplicateName>
|
|
19
19
|
| DataTrackPublishError<DataTrackPublishErrorReason.InvalidName>
|
|
20
|
-
| DataTrackPublishError<DataTrackPublishErrorReason.LimitReached
|
|
20
|
+
| DataTrackPublishError<DataTrackPublishErrorReason.LimitReached>
|
|
21
|
+
| DataTrackPublishError<DataTrackPublishErrorReason.Unknown>;
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
/** Request sent to the SFU to publish a track. */
|
|
@@ -36,7 +37,7 @@ export type EventSfuUnpublishRequest = {
|
|
|
36
37
|
export type EventPacketAvailable = {
|
|
37
38
|
/** The handle associated with the data track which this packet bytes belong to. */
|
|
38
39
|
handle: DataTrackHandle;
|
|
39
|
-
bytes:
|
|
40
|
+
bytes: NonSharedUint8Array;
|
|
40
41
|
};
|
|
41
42
|
|
|
42
43
|
/** A track has been created by a local participant and is available to be
|
|
@@ -75,9 +75,9 @@ export class DataTrackE2eeExtension extends DataTrackExtension {
|
|
|
75
75
|
|
|
76
76
|
keyIndex: number;
|
|
77
77
|
|
|
78
|
-
iv:
|
|
78
|
+
iv: NonSharedUint8Array; /* NOTE: According to the rust implementation, this should be 12 bytes long. */
|
|
79
79
|
|
|
80
|
-
constructor(keyIndex: number, iv:
|
|
80
|
+
constructor(keyIndex: number, iv: NonSharedUint8Array) {
|
|
81
81
|
super();
|
|
82
82
|
this.keyIndex = keyIndex;
|
|
83
83
|
this.iv = iv;
|
|
@@ -300,9 +300,9 @@ export enum FrameMarker {
|
|
|
300
300
|
export class DataTrackPacket extends Serializable {
|
|
301
301
|
header: DataTrackPacketHeader;
|
|
302
302
|
|
|
303
|
-
payload:
|
|
303
|
+
payload: NonSharedUint8Array;
|
|
304
304
|
|
|
305
|
-
constructor(header: DataTrackPacketHeader, payload:
|
|
305
|
+
constructor(header: DataTrackPacketHeader, payload: NonSharedUint8Array) {
|
|
306
306
|
super();
|
|
307
307
|
this.header = header;
|
|
308
308
|
this.payload = payload;
|
|
@@ -349,10 +349,10 @@ export class DataTrackPacket extends Serializable {
|
|
|
349
349
|
dataView.byteOffset + dataView.byteLength,
|
|
350
350
|
);
|
|
351
351
|
|
|
352
|
-
return [
|
|
353
|
-
DataTrackPacket,
|
|
354
|
-
|
|
355
|
-
];
|
|
352
|
+
return [
|
|
353
|
+
new DataTrackPacket(header, new Uint8Array(payload) as NonSharedUint8Array),
|
|
354
|
+
dataView.byteLength,
|
|
355
|
+
] as [DataTrackPacket, number];
|
|
356
356
|
}
|
|
357
357
|
|
|
358
358
|
toJSON() {
|
|
@@ -10,7 +10,7 @@ export default abstract class Serializable {
|
|
|
10
10
|
abstract toBinaryInto(dataView: DataView): Throws<number, DataTrackSerializeError>;
|
|
11
11
|
|
|
12
12
|
/** Encodes the instance as binary and returns the data as a Uint8Array. */
|
|
13
|
-
toBinary(): Throws<
|
|
13
|
+
toBinary(): Throws<NonSharedUint8Array, DataTrackSerializeError> {
|
|
14
14
|
const lengthBytes = this.toBinaryLengthBytes();
|
|
15
15
|
const output = new ArrayBuffer(lengthBytes);
|
|
16
16
|
const view = new DataView(output);
|
|
@@ -11,6 +11,14 @@ export type DataTrackInfo = {
|
|
|
11
11
|
usesE2ee: boolean;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
+
export type RemoteDataTrackPipelineOptions = {
|
|
15
|
+
/** Set the maximum number of in-flight partial frames the depacketizer will track
|
|
16
|
+
* concurrently for this track. Higher values give more out-of-order tolerance for
|
|
17
|
+
* high-frequency senders. Defaults to 1.
|
|
18
|
+
*/
|
|
19
|
+
maxPartialFrames?: number;
|
|
20
|
+
};
|
|
21
|
+
|
|
14
22
|
export const DataTrackInfo = {
|
|
15
23
|
from(protocolInfo: ProtocolDataTrackInfo): DataTrackInfo {
|
|
16
24
|
return {
|
package/src/room/events.ts
CHANGED
|
@@ -225,7 +225,7 @@ export enum RoomEvent {
|
|
|
225
225
|
* Data packets provides the ability to use LiveKit to send/receive arbitrary payloads.
|
|
226
226
|
* All participants in the room will receive the messages sent to the room.
|
|
227
227
|
*
|
|
228
|
-
* args: (payload:
|
|
228
|
+
* args: (payload: NonSharedUint8Array, participant: [[Participant]], kind: [[DataPacket_Kind]], topic?: string)
|
|
229
229
|
*/
|
|
230
230
|
DataReceived = 'dataReceived',
|
|
231
231
|
|
|
@@ -489,7 +489,7 @@ export enum ParticipantEvent {
|
|
|
489
489
|
* Data packets provides the ability to use LiveKit to send/receive arbitrary payloads.
|
|
490
490
|
* All participants in the room will receive the messages sent to the room.
|
|
491
491
|
*
|
|
492
|
-
* args: (payload:
|
|
492
|
+
* args: (payload: NonSharedUint8Array, kind: [[DataPacket_Kind]])
|
|
493
493
|
*/
|
|
494
494
|
DataReceived = 'dataReceived',
|
|
495
495
|
|