livekit-client 2.17.0 → 2.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/livekit-client.e2ee.worker.js +1 -1
- package/dist/livekit-client.e2ee.worker.js.map +1 -1
- package/dist/livekit-client.e2ee.worker.mjs +7 -2
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +2350 -1430
- package/dist/livekit-client.esm.mjs.map +1 -1
- package/dist/livekit-client.umd.js +1 -1
- package/dist/livekit-client.umd.js.map +1 -1
- package/dist/src/e2ee/KeyProvider.d.ts +4 -2
- package/dist/src/e2ee/KeyProvider.d.ts.map +1 -1
- package/dist/src/index.d.ts +9 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/logger.d.ts +2 -1
- package/dist/src/logger.d.ts.map +1 -1
- package/dist/src/room/PCTransport.d.ts.map +1 -1
- package/dist/src/room/PCTransportManager.d.ts.map +1 -1
- package/dist/src/room/RTCEngine.d.ts.map +1 -1
- package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts.map +1 -1
- package/dist/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts.map +1 -1
- package/dist/src/room/data-track/depacketizer.d.ts +51 -0
- package/dist/src/room/data-track/depacketizer.d.ts.map +1 -0
- package/dist/src/room/data-track/frame.d.ts +7 -0
- package/dist/src/room/data-track/frame.d.ts.map +1 -0
- package/dist/src/room/data-track/handle.d.ts +27 -0
- package/dist/src/room/data-track/handle.d.ts.map +1 -0
- package/dist/src/room/data-track/packet/constants.d.ts +20 -0
- package/dist/src/room/data-track/packet/constants.d.ts.map +1 -0
- package/dist/src/room/data-track/packet/errors.d.ts +42 -0
- package/dist/src/room/data-track/packet/errors.d.ts.map +1 -0
- package/dist/src/room/data-track/packet/extensions.d.ts +68 -0
- package/dist/src/room/data-track/packet/extensions.d.ts.map +1 -0
- package/dist/src/room/data-track/packet/index.d.ts +91 -0
- package/dist/src/room/data-track/packet/index.d.ts.map +1 -0
- package/dist/src/room/data-track/packet/serializable.d.ts +12 -0
- package/dist/src/room/data-track/packet/serializable.d.ts.map +1 -0
- package/dist/src/room/data-track/packetizer.d.ts +43 -0
- package/dist/src/room/data-track/packetizer.d.ts.map +1 -0
- package/dist/src/room/data-track/utils.d.ts +60 -0
- package/dist/src/room/data-track/utils.d.ts.map +1 -0
- package/dist/src/room/errors.d.ts +16 -4
- package/dist/src/room/errors.d.ts.map +1 -1
- package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +1 -0
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/types.d.ts +1 -0
- package/dist/src/room/types.d.ts.map +1 -1
- package/dist/src/utils/TypedPromise.d.ts +4 -0
- package/dist/src/utils/TypedPromise.d.ts.map +1 -1
- package/dist/src/utils/throws.d.ts +36 -0
- package/dist/src/utils/throws.d.ts.map +1 -0
- package/dist/ts4.2/e2ee/KeyProvider.d.ts +4 -2
- package/dist/ts4.2/index.d.ts +10 -3
- package/dist/ts4.2/logger.d.ts +2 -1
- package/dist/ts4.2/room/data-track/depacketizer.d.ts +51 -0
- package/dist/ts4.2/room/data-track/frame.d.ts +7 -0
- package/dist/ts4.2/room/data-track/handle.d.ts +27 -0
- package/dist/ts4.2/room/data-track/packet/constants.d.ts +20 -0
- package/dist/ts4.2/room/data-track/packet/errors.d.ts +42 -0
- package/dist/ts4.2/room/data-track/packet/extensions.d.ts +68 -0
- package/dist/ts4.2/room/data-track/packet/index.d.ts +98 -0
- package/dist/ts4.2/room/data-track/packet/serializable.d.ts +12 -0
- package/dist/ts4.2/room/data-track/packetizer.d.ts +43 -0
- package/dist/ts4.2/room/data-track/utils.d.ts +60 -0
- package/dist/ts4.2/room/errors.d.ts +16 -4
- package/dist/ts4.2/room/track/LocalTrack.d.ts +1 -0
- package/dist/ts4.2/room/types.d.ts +1 -0
- package/dist/ts4.2/utils/TypedPromise.d.ts +4 -0
- package/dist/ts4.2/utils/throws.d.ts +39 -0
- package/package.json +12 -10
- package/src/e2ee/KeyProvider.ts +4 -2
- package/src/index.ts +21 -5
- package/src/logger.ts +1 -0
- package/src/room/PCTransport.ts +1 -0
- package/src/room/PCTransportManager.ts +27 -9
- package/src/room/RTCEngine.ts +13 -2
- package/src/room/Room.ts +1 -1
- package/src/room/data-stream/incoming/IncomingDataStreamManager.ts +1 -0
- package/src/room/data-stream/outgoing/OutgoingDataStreamManager.ts +2 -1
- package/src/room/data-track/depacketizer.test.ts +442 -0
- package/src/room/data-track/depacketizer.ts +298 -0
- package/src/room/data-track/frame.ts +8 -0
- package/src/room/data-track/handle.test.ts +13 -0
- package/src/room/data-track/handle.ts +80 -0
- package/src/room/data-track/packet/constants.ts +27 -0
- package/src/room/data-track/packet/errors.ts +121 -0
- package/src/room/data-track/packet/extensions.ts +259 -0
- package/src/room/data-track/packet/index.test.ts +615 -0
- package/src/room/data-track/packet/index.ts +363 -0
- package/src/room/data-track/packet/serializable.ts +29 -0
- package/src/room/data-track/packetizer.test.ts +131 -0
- package/src/room/data-track/packetizer.ts +128 -0
- package/src/room/data-track/utils.test.ts +54 -0
- package/src/room/data-track/utils.ts +206 -0
- package/src/room/errors.ts +23 -5
- package/src/room/track/LocalAudioTrack.ts +4 -7
- package/src/room/track/LocalTrack.ts +4 -0
- package/src/room/types.ts +3 -1
- package/src/utils/TypedPromise.ts +7 -0
- package/src/utils/throws.ts +42 -0
|
@@ -0,0 +1,615 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { DataTrackPacket, DataTrackPacketHeader, FrameMarker } from '.';
|
|
4
|
+
import { DataTrackHandle } from '../handle';
|
|
5
|
+
import { DataTrackTimestamp, WrapAroundUnsignedInt } from '../utils';
|
|
6
|
+
import { EXT_FLAG_SHIFT } from './constants';
|
|
7
|
+
import {
|
|
8
|
+
DataTrackE2eeExtension,
|
|
9
|
+
DataTrackExtensionTag,
|
|
10
|
+
DataTrackExtensions,
|
|
11
|
+
DataTrackUserTimestampExtension,
|
|
12
|
+
} from './extensions';
|
|
13
|
+
|
|
14
|
+
describe('DataTrackPacket', () => {
|
|
15
|
+
describe('Serialization', () => {
|
|
16
|
+
it('should serialize a single packet', () => {
|
|
17
|
+
const header = new DataTrackPacketHeader({
|
|
18
|
+
marker: FrameMarker.Single,
|
|
19
|
+
trackHandle: DataTrackHandle.fromNumber(101),
|
|
20
|
+
sequence: WrapAroundUnsignedInt.u16(102),
|
|
21
|
+
frameNumber: WrapAroundUnsignedInt.u16(103),
|
|
22
|
+
timestamp: DataTrackTimestamp.fromRtpTicks(104),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const payloadBytes = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
|
26
|
+
|
|
27
|
+
const packet = new DataTrackPacket(header, payloadBytes);
|
|
28
|
+
|
|
29
|
+
expect(packet.toBinaryLengthBytes()).toStrictEqual(22);
|
|
30
|
+
expect(packet.toBinary()).toStrictEqual(
|
|
31
|
+
new Uint8Array([
|
|
32
|
+
0x18, // Version 0, single, extension
|
|
33
|
+
0, // Reserved
|
|
34
|
+
0, // Track handle (big endian)
|
|
35
|
+
101,
|
|
36
|
+
0, // Sequence (big endian)
|
|
37
|
+
102,
|
|
38
|
+
0, // Frame number (big endian)
|
|
39
|
+
103,
|
|
40
|
+
0, // Timestamp (big endian)
|
|
41
|
+
0,
|
|
42
|
+
0,
|
|
43
|
+
104,
|
|
44
|
+
/* (No extension words value) */
|
|
45
|
+
0, // Payload
|
|
46
|
+
1,
|
|
47
|
+
2,
|
|
48
|
+
3,
|
|
49
|
+
4,
|
|
50
|
+
5,
|
|
51
|
+
6,
|
|
52
|
+
7,
|
|
53
|
+
8,
|
|
54
|
+
9,
|
|
55
|
+
]),
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
it('should serialize a final packet with extensions', () => {
|
|
59
|
+
const header = new DataTrackPacketHeader({
|
|
60
|
+
marker: FrameMarker.Final,
|
|
61
|
+
trackHandle: DataTrackHandle.fromNumber(0x8811),
|
|
62
|
+
sequence: WrapAroundUnsignedInt.u16(0x4422),
|
|
63
|
+
frameNumber: WrapAroundUnsignedInt.u16(0x4411),
|
|
64
|
+
timestamp: DataTrackTimestamp.fromRtpTicks(0x44221188),
|
|
65
|
+
extensions: new DataTrackExtensions({
|
|
66
|
+
userTimestamp: new DataTrackUserTimestampExtension(0x4411221111118811n),
|
|
67
|
+
e2ee: new DataTrackE2eeExtension(0xfa, new Uint8Array(12).fill(0x3c)),
|
|
68
|
+
}),
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const payloadBytes = new Uint8Array(32).fill(0xfa);
|
|
72
|
+
|
|
73
|
+
const packet = new DataTrackPacket(header, payloadBytes);
|
|
74
|
+
|
|
75
|
+
expect(packet.toBinaryLengthBytes()).toStrictEqual(78);
|
|
76
|
+
expect(packet.toBinary()).toStrictEqual(
|
|
77
|
+
new Uint8Array([
|
|
78
|
+
0xc, // Version 0, final, extension
|
|
79
|
+
0, // Reserved
|
|
80
|
+
136, // Track handle (big endian)
|
|
81
|
+
17,
|
|
82
|
+
68, // Sequence (big endian)
|
|
83
|
+
34,
|
|
84
|
+
68, // Frame number (big endian)
|
|
85
|
+
17,
|
|
86
|
+
68, // Timestamp (big endian)
|
|
87
|
+
34,
|
|
88
|
+
17,
|
|
89
|
+
136,
|
|
90
|
+
0, // Rtp oriented extension words (big endian)
|
|
91
|
+
7,
|
|
92
|
+
|
|
93
|
+
// E2ee extension
|
|
94
|
+
0, // ID 1 (big endian)
|
|
95
|
+
1,
|
|
96
|
+
0, // Length 12 (big endian)
|
|
97
|
+
12,
|
|
98
|
+
0xfa, // Key index
|
|
99
|
+
0x3c, // Iv array
|
|
100
|
+
0x3c,
|
|
101
|
+
0x3c,
|
|
102
|
+
0x3c,
|
|
103
|
+
0x3c,
|
|
104
|
+
0x3c,
|
|
105
|
+
0x3c,
|
|
106
|
+
0x3c,
|
|
107
|
+
0x3c,
|
|
108
|
+
0x3c,
|
|
109
|
+
0x3c,
|
|
110
|
+
0x3c,
|
|
111
|
+
|
|
112
|
+
// User timestamp extension
|
|
113
|
+
0, // ID 2 (big endian)
|
|
114
|
+
2,
|
|
115
|
+
0, // Length 7 (big endian)
|
|
116
|
+
7,
|
|
117
|
+
68, // Timestamp value (big endian)
|
|
118
|
+
17,
|
|
119
|
+
34,
|
|
120
|
+
17,
|
|
121
|
+
17,
|
|
122
|
+
17,
|
|
123
|
+
136,
|
|
124
|
+
17,
|
|
125
|
+
|
|
126
|
+
0, // Extension padding
|
|
127
|
+
0,
|
|
128
|
+
0,
|
|
129
|
+
|
|
130
|
+
0xfa, // Payload
|
|
131
|
+
0xfa,
|
|
132
|
+
0xfa,
|
|
133
|
+
0xfa,
|
|
134
|
+
0xfa,
|
|
135
|
+
0xfa,
|
|
136
|
+
0xfa,
|
|
137
|
+
0xfa,
|
|
138
|
+
0xfa,
|
|
139
|
+
0xfa,
|
|
140
|
+
0xfa,
|
|
141
|
+
0xfa,
|
|
142
|
+
0xfa,
|
|
143
|
+
0xfa,
|
|
144
|
+
0xfa,
|
|
145
|
+
0xfa,
|
|
146
|
+
0xfa,
|
|
147
|
+
0xfa,
|
|
148
|
+
0xfa,
|
|
149
|
+
0xfa,
|
|
150
|
+
0xfa,
|
|
151
|
+
0xfa,
|
|
152
|
+
0xfa,
|
|
153
|
+
0xfa,
|
|
154
|
+
0xfa,
|
|
155
|
+
0xfa,
|
|
156
|
+
0xfa,
|
|
157
|
+
0xfa,
|
|
158
|
+
0xfa,
|
|
159
|
+
0xfa,
|
|
160
|
+
0xfa,
|
|
161
|
+
0xfa,
|
|
162
|
+
]),
|
|
163
|
+
);
|
|
164
|
+
});
|
|
165
|
+
it('should serialize a start packet with only the e2ee extension', () => {
|
|
166
|
+
const header = new DataTrackPacketHeader({
|
|
167
|
+
marker: FrameMarker.Start,
|
|
168
|
+
trackHandle: DataTrackHandle.fromNumber(101),
|
|
169
|
+
sequence: WrapAroundUnsignedInt.u16(102),
|
|
170
|
+
frameNumber: WrapAroundUnsignedInt.u16(103),
|
|
171
|
+
timestamp: DataTrackTimestamp.fromRtpTicks(104),
|
|
172
|
+
extensions: new DataTrackExtensions({
|
|
173
|
+
e2ee: new DataTrackE2eeExtension(0xfa, new Uint8Array(12).fill(0x3c)),
|
|
174
|
+
}),
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const payloadBytes = new Uint8Array(32).fill(0xfa);
|
|
178
|
+
|
|
179
|
+
const packet = new DataTrackPacket(header, payloadBytes);
|
|
180
|
+
|
|
181
|
+
expect(packet.toBinaryLengthBytes()).toStrictEqual(66);
|
|
182
|
+
expect(packet.toBinary()).toStrictEqual(
|
|
183
|
+
new Uint8Array([
|
|
184
|
+
0x14, // Version 0, start, extension
|
|
185
|
+
0, // Reserved
|
|
186
|
+
0, // Track handle (big endian)
|
|
187
|
+
101,
|
|
188
|
+
0, // Sequence (big endian)
|
|
189
|
+
102,
|
|
190
|
+
0, // Frame number (big endian)
|
|
191
|
+
103,
|
|
192
|
+
0, // Timestamp (big endian)
|
|
193
|
+
0,
|
|
194
|
+
0,
|
|
195
|
+
104,
|
|
196
|
+
0, // RTP oriented extension words (big endian)
|
|
197
|
+
4,
|
|
198
|
+
|
|
199
|
+
// E2ee extension
|
|
200
|
+
0, // ID 1 (big endian)
|
|
201
|
+
1,
|
|
202
|
+
0, // Length 12 (big endian)
|
|
203
|
+
12,
|
|
204
|
+
0xfa, // Key index
|
|
205
|
+
0x3c, // Iv array
|
|
206
|
+
0x3c,
|
|
207
|
+
0x3c,
|
|
208
|
+
0x3c,
|
|
209
|
+
0x3c,
|
|
210
|
+
0x3c,
|
|
211
|
+
0x3c,
|
|
212
|
+
0x3c,
|
|
213
|
+
0x3c,
|
|
214
|
+
0x3c,
|
|
215
|
+
0x3c,
|
|
216
|
+
0x3c,
|
|
217
|
+
|
|
218
|
+
0, // Extension padding
|
|
219
|
+
0,
|
|
220
|
+
0,
|
|
221
|
+
|
|
222
|
+
0xfa, // Payload
|
|
223
|
+
0xfa,
|
|
224
|
+
0xfa,
|
|
225
|
+
0xfa,
|
|
226
|
+
0xfa,
|
|
227
|
+
0xfa,
|
|
228
|
+
0xfa,
|
|
229
|
+
0xfa,
|
|
230
|
+
0xfa,
|
|
231
|
+
0xfa,
|
|
232
|
+
0xfa,
|
|
233
|
+
0xfa,
|
|
234
|
+
0xfa,
|
|
235
|
+
0xfa,
|
|
236
|
+
0xfa,
|
|
237
|
+
0xfa,
|
|
238
|
+
0xfa,
|
|
239
|
+
0xfa,
|
|
240
|
+
0xfa,
|
|
241
|
+
0xfa,
|
|
242
|
+
0xfa,
|
|
243
|
+
0xfa,
|
|
244
|
+
0xfa,
|
|
245
|
+
0xfa,
|
|
246
|
+
0xfa,
|
|
247
|
+
0xfa,
|
|
248
|
+
0xfa,
|
|
249
|
+
0xfa,
|
|
250
|
+
0xfa,
|
|
251
|
+
0xfa,
|
|
252
|
+
0xfa,
|
|
253
|
+
0xfa,
|
|
254
|
+
]),
|
|
255
|
+
);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('should be unable to serialize a packet header into a DataView which is too small', () => {
|
|
259
|
+
const header = new DataTrackPacketHeader({
|
|
260
|
+
marker: FrameMarker.Single,
|
|
261
|
+
trackHandle: DataTrackHandle.fromNumber(101),
|
|
262
|
+
sequence: WrapAroundUnsignedInt.u16(102),
|
|
263
|
+
frameNumber: WrapAroundUnsignedInt.u16(103),
|
|
264
|
+
timestamp: DataTrackTimestamp.fromRtpTicks(104),
|
|
265
|
+
});
|
|
266
|
+
const payloadBytes = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
|
267
|
+
const packet = new DataTrackPacket(header, payloadBytes);
|
|
268
|
+
|
|
269
|
+
const twoByteLongDataView = new DataView(new ArrayBuffer(2));
|
|
270
|
+
expect(() => packet.toBinaryInto(twoByteLongDataView)).toThrow('Buffer cannot fit header');
|
|
271
|
+
});
|
|
272
|
+
it('should be unable to serialize a packet payload into a DataView which is too small', () => {
|
|
273
|
+
const header = new DataTrackPacketHeader({
|
|
274
|
+
marker: FrameMarker.Single,
|
|
275
|
+
trackHandle: DataTrackHandle.fromNumber(101),
|
|
276
|
+
sequence: WrapAroundUnsignedInt.u16(102),
|
|
277
|
+
frameNumber: WrapAroundUnsignedInt.u16(103),
|
|
278
|
+
timestamp: DataTrackTimestamp.fromRtpTicks(104),
|
|
279
|
+
});
|
|
280
|
+
const payloadBytes = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
|
281
|
+
const packet = new DataTrackPacket(header, payloadBytes);
|
|
282
|
+
|
|
283
|
+
const fourteenByteLongDataView = new DataView(
|
|
284
|
+
new ArrayBuffer(14 /* 12 byte header + 2 extra bytes */),
|
|
285
|
+
);
|
|
286
|
+
expect(() => packet.toBinaryInto(fourteenByteLongDataView)).toThrow(
|
|
287
|
+
'Buffer cannot fit payload',
|
|
288
|
+
);
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
describe('Deserialization', () => {
|
|
293
|
+
const VALID_PACKET_BYTES = [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
294
|
+
|
|
295
|
+
it('should deserialize a single packet', () => {
|
|
296
|
+
const [packet, bytes] = DataTrackPacket.fromBinary(
|
|
297
|
+
new Uint8Array([
|
|
298
|
+
0x18, // Version 0, single, extension
|
|
299
|
+
0, // Reserved
|
|
300
|
+
0, // Track handle (big endian)
|
|
301
|
+
101,
|
|
302
|
+
0, // Sequence (big endian)
|
|
303
|
+
102,
|
|
304
|
+
0, // Frame number (big endian)
|
|
305
|
+
103,
|
|
306
|
+
0, // Timestamp (big endian)
|
|
307
|
+
0,
|
|
308
|
+
0,
|
|
309
|
+
104,
|
|
310
|
+
/* (No extension words value) */
|
|
311
|
+
1, // Payload
|
|
312
|
+
2,
|
|
313
|
+
3,
|
|
314
|
+
4,
|
|
315
|
+
5,
|
|
316
|
+
6,
|
|
317
|
+
7,
|
|
318
|
+
8,
|
|
319
|
+
9,
|
|
320
|
+
]),
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
expect(bytes).toStrictEqual(21);
|
|
324
|
+
expect(packet.toJSON()).toStrictEqual({
|
|
325
|
+
header: {
|
|
326
|
+
frameNumber: 103,
|
|
327
|
+
marker: FrameMarker.Single,
|
|
328
|
+
sequence: 102,
|
|
329
|
+
timestamp: 104,
|
|
330
|
+
trackHandle: 101,
|
|
331
|
+
extensions: {
|
|
332
|
+
e2ee: null,
|
|
333
|
+
userTimestamp: null,
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
payload: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9]),
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it('should fail to deserialize a too short buffer', () => {
|
|
341
|
+
const packetBytes = new Uint8Array(VALID_PACKET_BYTES);
|
|
342
|
+
|
|
343
|
+
expect(() => DataTrackPacket.fromBinary(packetBytes.slice(0, 5))).toThrow(
|
|
344
|
+
'Too short to contain a valid header',
|
|
345
|
+
);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it('should fail to deserialize a packet including extensions but missing the ext words value', () => {
|
|
349
|
+
const packetBytes = new Uint8Array(VALID_PACKET_BYTES);
|
|
350
|
+
packetBytes[0] |= 1 << EXT_FLAG_SHIFT; // Extension flag - should have ext word indicator here
|
|
351
|
+
|
|
352
|
+
expect(() => DataTrackPacket.fromBinary(packetBytes)).toThrow(
|
|
353
|
+
'Extension word indicator is missing',
|
|
354
|
+
);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('should fail to deserialize a packet which overruns headers', () => {
|
|
358
|
+
const packetBytes = new Uint8Array([
|
|
359
|
+
...VALID_PACKET_BYTES,
|
|
360
|
+
|
|
361
|
+
0, // Extension word (big endian)
|
|
362
|
+
1,
|
|
363
|
+
]);
|
|
364
|
+
packetBytes[0] |= 1 << EXT_FLAG_SHIFT; // Extension flag - should have ext word indicator here
|
|
365
|
+
|
|
366
|
+
expect(() => DataTrackPacket.fromBinary(packetBytes)).toThrow(
|
|
367
|
+
'Header exceeds total packet length',
|
|
368
|
+
);
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it('should fail to deserialize a packet with an unsupported version', () => {
|
|
372
|
+
const packetBytes = new Uint8Array(VALID_PACKET_BYTES);
|
|
373
|
+
packetBytes[0] = 0x20; // Version 1 (not supported yet)
|
|
374
|
+
|
|
375
|
+
expect(() => DataTrackPacket.fromBinary(packetBytes)).toThrow('Unsupported version 1');
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it('should deserialize base header', () => {
|
|
379
|
+
const [packet, bytes] = DataTrackPacket.fromBinary(
|
|
380
|
+
new Uint8Array([
|
|
381
|
+
0x8, // Version 0, final, extension
|
|
382
|
+
0x0, // Reserved
|
|
383
|
+
0x88, // Track handle (big endian)
|
|
384
|
+
0x11,
|
|
385
|
+
0x44, // Sequence (big endian)
|
|
386
|
+
0x22,
|
|
387
|
+
0x44, // Frame number (big endian)
|
|
388
|
+
0x11,
|
|
389
|
+
0x44, // Timestamp (big endian)
|
|
390
|
+
0x22,
|
|
391
|
+
0x11,
|
|
392
|
+
0x88,
|
|
393
|
+
]),
|
|
394
|
+
);
|
|
395
|
+
|
|
396
|
+
expect(bytes).toStrictEqual(12);
|
|
397
|
+
expect(packet.toJSON()).toStrictEqual({
|
|
398
|
+
header: {
|
|
399
|
+
marker: FrameMarker.Final,
|
|
400
|
+
trackHandle: 0x8811,
|
|
401
|
+
sequence: 0x4422,
|
|
402
|
+
frameNumber: 0x4411,
|
|
403
|
+
timestamp: 0x44221188,
|
|
404
|
+
extensions: {
|
|
405
|
+
e2ee: null,
|
|
406
|
+
userTimestamp: null,
|
|
407
|
+
},
|
|
408
|
+
},
|
|
409
|
+
payload: new Uint8Array([]),
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
it.each([0, 1, 24])('should skip extension padding', (extensionWords) => {
|
|
414
|
+
const packetBytes = new Uint8Array([
|
|
415
|
+
...VALID_PACKET_BYTES,
|
|
416
|
+
|
|
417
|
+
0, // Extension words (big endian)
|
|
418
|
+
extensionWords,
|
|
419
|
+
|
|
420
|
+
...new Array((extensionWords + 1) /* RTP oriented extension words */ * 4).fill(0), // Padding
|
|
421
|
+
]);
|
|
422
|
+
packetBytes[0] |= 1 << EXT_FLAG_SHIFT; // Extension flag
|
|
423
|
+
|
|
424
|
+
const [packet] = DataTrackPacket.fromBinary(packetBytes);
|
|
425
|
+
|
|
426
|
+
expect(new Uint8Array(packet.toJSON().payload).byteLength).toStrictEqual(0);
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
it('should deserialize e2ee extension properly', () => {
|
|
430
|
+
const packetBytes = new Uint8Array([
|
|
431
|
+
...VALID_PACKET_BYTES,
|
|
432
|
+
|
|
433
|
+
0, // RTP oriented extension words (big endian)
|
|
434
|
+
4,
|
|
435
|
+
|
|
436
|
+
// E2ee extension
|
|
437
|
+
0, // ID 1 (big endian)
|
|
438
|
+
1,
|
|
439
|
+
0, // Length 12 (big endian)
|
|
440
|
+
12,
|
|
441
|
+
0xfa, // Key index
|
|
442
|
+
0x3c, // Iv array
|
|
443
|
+
0x3c,
|
|
444
|
+
0x3c,
|
|
445
|
+
0x3c,
|
|
446
|
+
0x3c,
|
|
447
|
+
0x3c,
|
|
448
|
+
0x3c,
|
|
449
|
+
0x3c,
|
|
450
|
+
0x3c,
|
|
451
|
+
0x3c,
|
|
452
|
+
0x3c,
|
|
453
|
+
0x3c,
|
|
454
|
+
|
|
455
|
+
0, // Padding
|
|
456
|
+
0,
|
|
457
|
+
0,
|
|
458
|
+
]);
|
|
459
|
+
packetBytes[0] |= 1 << EXT_FLAG_SHIFT; // Extension flag
|
|
460
|
+
|
|
461
|
+
const [packet] = DataTrackPacket.fromBinary(packetBytes);
|
|
462
|
+
|
|
463
|
+
expect(packet.toJSON().header.extensions.e2ee).toStrictEqual({
|
|
464
|
+
tag: DataTrackExtensionTag.E2ee,
|
|
465
|
+
lengthBytes: 13,
|
|
466
|
+
keyIndex: 0xfa,
|
|
467
|
+
iv: new Uint8Array(12).fill(0x3c),
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
it('should deserialize user timestamp extension properly', () => {
|
|
472
|
+
const packetBytes = new Uint8Array([
|
|
473
|
+
...VALID_PACKET_BYTES,
|
|
474
|
+
|
|
475
|
+
0, // Extension words (big endian)
|
|
476
|
+
2,
|
|
477
|
+
|
|
478
|
+
// User timestamp extension
|
|
479
|
+
0, // ID 2 (big endian)
|
|
480
|
+
2,
|
|
481
|
+
0, // Length 7 (big endian)
|
|
482
|
+
7,
|
|
483
|
+
0x44, // Timestamp (big endian)
|
|
484
|
+
0x11,
|
|
485
|
+
0x22,
|
|
486
|
+
0x11,
|
|
487
|
+
0x11,
|
|
488
|
+
0x11,
|
|
489
|
+
0x88,
|
|
490
|
+
0x11,
|
|
491
|
+
]);
|
|
492
|
+
packetBytes[0] |= 1 << EXT_FLAG_SHIFT; // Extension flag
|
|
493
|
+
|
|
494
|
+
const [packet] = DataTrackPacket.fromBinary(packetBytes);
|
|
495
|
+
|
|
496
|
+
expect(packet.toJSON().header.extensions.userTimestamp).toStrictEqual({
|
|
497
|
+
tag: DataTrackExtensionTag.UserTimestamp,
|
|
498
|
+
lengthBytes: 8,
|
|
499
|
+
timestamp: 0x4411221111118811n,
|
|
500
|
+
});
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
it('should deserialize unknown extension properly', () => {
|
|
504
|
+
const packetBytes = new Uint8Array([
|
|
505
|
+
...VALID_PACKET_BYTES,
|
|
506
|
+
|
|
507
|
+
0, // RTP oriented extension words (big endian)
|
|
508
|
+
2,
|
|
509
|
+
|
|
510
|
+
// Unknown / potential future extension
|
|
511
|
+
0, // ID 8 (big endian)
|
|
512
|
+
8,
|
|
513
|
+
0, // Length 12 (big endian)
|
|
514
|
+
6,
|
|
515
|
+
0x1, // Payload
|
|
516
|
+
0x2,
|
|
517
|
+
0x3,
|
|
518
|
+
0x4,
|
|
519
|
+
0x5,
|
|
520
|
+
0x6,
|
|
521
|
+
|
|
522
|
+
0x0, // Padding
|
|
523
|
+
0x0,
|
|
524
|
+
]);
|
|
525
|
+
packetBytes[0] |= 1 << EXT_FLAG_SHIFT; // Extension flag
|
|
526
|
+
|
|
527
|
+
const [packet] = DataTrackPacket.fromBinary(packetBytes);
|
|
528
|
+
|
|
529
|
+
expect(packet.toJSON().header.extensions).toStrictEqual({
|
|
530
|
+
userTimestamp: null,
|
|
531
|
+
e2ee: null,
|
|
532
|
+
});
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
it('should ensure extensions are word aligned', () => {
|
|
536
|
+
const packetBytes = new Uint8Array([
|
|
537
|
+
...VALID_PACKET_BYTES,
|
|
538
|
+
|
|
539
|
+
0, // RTP oriented extension words (big endian)
|
|
540
|
+
0,
|
|
541
|
+
|
|
542
|
+
0x0, // Padding, missing one byte
|
|
543
|
+
0x0,
|
|
544
|
+
0x0,
|
|
545
|
+
]);
|
|
546
|
+
packetBytes[0] |= 1 << EXT_FLAG_SHIFT; // Extension flag
|
|
547
|
+
|
|
548
|
+
expect(() => DataTrackPacket.fromBinary(packetBytes)).toThrow(
|
|
549
|
+
'Header exceeds total packet length',
|
|
550
|
+
);
|
|
551
|
+
});
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
describe('Round trip serialization + deserialization', () => {
|
|
555
|
+
it('should serialize a single packet', () => {
|
|
556
|
+
const header = new DataTrackPacketHeader({
|
|
557
|
+
marker: FrameMarker.Single,
|
|
558
|
+
trackHandle: DataTrackHandle.fromNumber(101),
|
|
559
|
+
sequence: WrapAroundUnsignedInt.u16(102),
|
|
560
|
+
frameNumber: WrapAroundUnsignedInt.u16(103),
|
|
561
|
+
timestamp: DataTrackTimestamp.fromRtpTicks(104),
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
const payloadBytes = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
|
565
|
+
|
|
566
|
+
const encodedPacket = new DataTrackPacket(header, payloadBytes);
|
|
567
|
+
|
|
568
|
+
expect(encodedPacket.toBinaryLengthBytes()).toStrictEqual(21);
|
|
569
|
+
expect(encodedPacket.toBinary()).toStrictEqual(
|
|
570
|
+
new Uint8Array([
|
|
571
|
+
0x18, // Version 0, single, extension
|
|
572
|
+
0, // Reserved
|
|
573
|
+
0, // Track handle (big endian)
|
|
574
|
+
101,
|
|
575
|
+
0, // Sequence (big endian)
|
|
576
|
+
102,
|
|
577
|
+
0, // Frame number (big endian)
|
|
578
|
+
103,
|
|
579
|
+
0, // Timestamp (big endian)
|
|
580
|
+
0,
|
|
581
|
+
0,
|
|
582
|
+
104,
|
|
583
|
+
/* (No extension words value) */
|
|
584
|
+
1, // Payload
|
|
585
|
+
2,
|
|
586
|
+
3,
|
|
587
|
+
4,
|
|
588
|
+
5,
|
|
589
|
+
6,
|
|
590
|
+
7,
|
|
591
|
+
8,
|
|
592
|
+
9,
|
|
593
|
+
]),
|
|
594
|
+
);
|
|
595
|
+
|
|
596
|
+
const [decodedPacket, bytes] = DataTrackPacket.fromBinary(encodedPacket.toBinary());
|
|
597
|
+
|
|
598
|
+
expect(bytes).toStrictEqual(21);
|
|
599
|
+
expect(decodedPacket.toJSON()).toStrictEqual({
|
|
600
|
+
header: {
|
|
601
|
+
frameNumber: 103,
|
|
602
|
+
marker: FrameMarker.Single,
|
|
603
|
+
sequence: 102,
|
|
604
|
+
timestamp: 104,
|
|
605
|
+
trackHandle: 101,
|
|
606
|
+
extensions: {
|
|
607
|
+
e2ee: null,
|
|
608
|
+
userTimestamp: null,
|
|
609
|
+
},
|
|
610
|
+
},
|
|
611
|
+
payload: new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9]),
|
|
612
|
+
});
|
|
613
|
+
});
|
|
614
|
+
});
|
|
615
|
+
});
|