livekit-client 2.15.4 → 2.15.6
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 +373 -164
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +982 -643
- 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/E2eeManager.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts +0 -47
- package/dist/src/e2ee/worker/FrameCryptor.d.ts.map +1 -1
- package/dist/src/e2ee/worker/naluUtils.d.ts +27 -0
- package/dist/src/e2ee/worker/naluUtils.d.ts.map +1 -0
- package/dist/src/e2ee/worker/sifPayload.d.ts +22 -0
- package/dist/src/e2ee/worker/sifPayload.d.ts.map +1 -0
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/room/Room.d.ts +6 -10
- package/dist/src/room/Room.d.ts.map +1 -1
- package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts +20 -0
- package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts.map +1 -0
- package/dist/{ts4.2/src/room → src/room/data-stream/incoming}/StreamReader.d.ts +82 -56
- package/dist/src/room/data-stream/incoming/StreamReader.d.ts.map +1 -0
- package/dist/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts +27 -0
- package/dist/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts.map +1 -0
- package/dist/src/room/{StreamWriter.d.ts → data-stream/outgoing/StreamWriter.d.ts} +1 -1
- package/dist/src/room/data-stream/outgoing/StreamWriter.d.ts.map +1 -0
- package/dist/src/room/errors.d.ts +13 -0
- package/dist/src/room/errors.d.ts.map +1 -1
- package/dist/src/room/participant/LocalParticipant.d.ts +32 -19
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +7 -2
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/RemoteVideoTrack.d.ts +1 -0
- package/dist/src/room/track/RemoteVideoTrack.d.ts.map +1 -1
- package/dist/src/room/track/Track.d.ts +4 -1
- package/dist/src/room/track/Track.d.ts.map +1 -1
- package/dist/src/room/types.d.ts +17 -1
- package/dist/src/room/types.d.ts.map +1 -1
- package/dist/src/room/utils.d.ts +8 -0
- package/dist/src/room/utils.d.ts.map +1 -1
- package/dist/ts4.2/src/e2ee/worker/FrameCryptor.d.ts +0 -47
- package/dist/ts4.2/src/e2ee/worker/naluUtils.d.ts +27 -0
- package/dist/ts4.2/src/e2ee/worker/sifPayload.d.ts +22 -0
- package/dist/ts4.2/src/index.d.ts +2 -2
- package/dist/ts4.2/src/room/Room.d.ts +6 -10
- package/dist/ts4.2/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts +20 -0
- package/dist/{src/room → ts4.2/src/room/data-stream/incoming}/StreamReader.d.ts +82 -56
- package/dist/ts4.2/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts +27 -0
- package/dist/ts4.2/src/room/{StreamWriter.d.ts → data-stream/outgoing/StreamWriter.d.ts} +1 -1
- package/dist/ts4.2/src/room/errors.d.ts +13 -0
- package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +32 -19
- package/dist/ts4.2/src/room/track/LocalTrack.d.ts +7 -2
- package/dist/ts4.2/src/room/track/RemoteVideoTrack.d.ts +1 -0
- package/dist/ts4.2/src/room/track/Track.d.ts +4 -1
- package/dist/ts4.2/src/room/types.d.ts +17 -1
- package/dist/ts4.2/src/room/utils.d.ts +8 -0
- package/package.json +7 -7
- package/src/e2ee/E2eeManager.ts +18 -1
- package/src/e2ee/worker/FrameCryptor.ts +56 -157
- package/src/e2ee/worker/e2ee.worker.ts +6 -1
- package/src/e2ee/worker/naluUtils.ts +328 -0
- package/src/e2ee/worker/sifPayload.ts +75 -0
- package/src/index.ts +2 -2
- package/src/room/Room.ts +104 -208
- package/src/room/data-stream/incoming/IncomingDataStreamManager.ts +247 -0
- package/src/room/data-stream/incoming/StreamReader.ts +317 -0
- package/src/room/data-stream/outgoing/OutgoingDataStreamManager.ts +316 -0
- package/src/room/{StreamWriter.ts → data-stream/outgoing/StreamWriter.ts} +1 -1
- package/src/room/errors.ts +34 -0
- package/src/room/participant/LocalParticipant.ts +39 -295
- package/src/room/track/LocalAudioTrack.ts +2 -2
- package/src/room/track/LocalTrack.ts +70 -50
- package/src/room/track/RemoteVideoTrack.ts +12 -2
- package/src/room/track/Track.ts +10 -1
- package/src/room/types.ts +22 -1
- package/src/room/utils.ts +14 -5
- package/dist/src/e2ee/worker/SifGuard.d.ts +0 -11
- package/dist/src/e2ee/worker/SifGuard.d.ts.map +0 -1
- package/dist/src/room/StreamReader.d.ts.map +0 -1
- package/dist/src/room/StreamWriter.d.ts.map +0 -1
- package/dist/ts4.2/src/e2ee/worker/SifGuard.d.ts +0 -11
- package/src/e2ee/worker/SifGuard.ts +0 -47
- package/src/room/StreamReader.ts +0 -170
@@ -0,0 +1,328 @@
|
|
1
|
+
/**
|
2
|
+
* NALU (Network Abstraction Layer Unit) utilities for H.264 and H.265 video processing
|
3
|
+
* Contains functions for parsing and working with NALUs in video frames
|
4
|
+
*/
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Mask for extracting NALU type from H.264 header byte
|
8
|
+
*/
|
9
|
+
const kH264NaluTypeMask = 0x1f;
|
10
|
+
|
11
|
+
/**
|
12
|
+
* H.264 NALU types according to RFC 6184
|
13
|
+
*/
|
14
|
+
enum H264NALUType {
|
15
|
+
/** Coded slice of a non-IDR picture */
|
16
|
+
SLICE_NON_IDR = 1,
|
17
|
+
/** Coded slice data partition A */
|
18
|
+
SLICE_PARTITION_A = 2,
|
19
|
+
/** Coded slice data partition B */
|
20
|
+
SLICE_PARTITION_B = 3,
|
21
|
+
/** Coded slice data partition C */
|
22
|
+
SLICE_PARTITION_C = 4,
|
23
|
+
/** Coded slice of an IDR picture */
|
24
|
+
SLICE_IDR = 5,
|
25
|
+
/** Supplemental enhancement information */
|
26
|
+
SEI = 6,
|
27
|
+
/** Sequence parameter set */
|
28
|
+
SPS = 7,
|
29
|
+
/** Picture parameter set */
|
30
|
+
PPS = 8,
|
31
|
+
/** Access unit delimiter */
|
32
|
+
AUD = 9,
|
33
|
+
/** End of sequence */
|
34
|
+
END_SEQ = 10,
|
35
|
+
/** End of stream */
|
36
|
+
END_STREAM = 11,
|
37
|
+
/** Filler data */
|
38
|
+
FILLER_DATA = 12,
|
39
|
+
/** Sequence parameter set extension */
|
40
|
+
SPS_EXT = 13,
|
41
|
+
/** Prefix NAL unit */
|
42
|
+
PREFIX_NALU = 14,
|
43
|
+
/** Subset sequence parameter set */
|
44
|
+
SUBSET_SPS = 15,
|
45
|
+
/** Depth parameter set */
|
46
|
+
DPS = 16,
|
47
|
+
|
48
|
+
// 17, 18 reserved
|
49
|
+
|
50
|
+
/** Coded slice of an auxiliary coded picture without partitioning */
|
51
|
+
SLICE_AUX = 19,
|
52
|
+
/** Coded slice extension */
|
53
|
+
SLICE_EXT = 20,
|
54
|
+
/** Coded slice extension for a depth view component or a 3D-AVC texture view component */
|
55
|
+
SLICE_LAYER_EXT = 21,
|
56
|
+
|
57
|
+
// 22, 23 reserved
|
58
|
+
}
|
59
|
+
|
60
|
+
/**
|
61
|
+
* H.265/HEVC NALU types according to ITU-T H.265
|
62
|
+
*/
|
63
|
+
enum H265NALUType {
|
64
|
+
/** Coded slice segment of a non-TSA, non-STSA trailing picture */
|
65
|
+
TRAIL_N = 0,
|
66
|
+
/** Coded slice segment of a non-TSA, non-STSA trailing picture */
|
67
|
+
TRAIL_R = 1,
|
68
|
+
/** Coded slice segment of a TSA picture */
|
69
|
+
TSA_N = 2,
|
70
|
+
/** Coded slice segment of a TSA picture */
|
71
|
+
TSA_R = 3,
|
72
|
+
/** Coded slice segment of an STSA picture */
|
73
|
+
STSA_N = 4,
|
74
|
+
/** Coded slice segment of an STSA picture */
|
75
|
+
STSA_R = 5,
|
76
|
+
/** Coded slice segment of a RADL picture */
|
77
|
+
RADL_N = 6,
|
78
|
+
/** Coded slice segment of a RADL picture */
|
79
|
+
RADL_R = 7,
|
80
|
+
/** Coded slice segment of a RASL picture */
|
81
|
+
RASL_N = 8,
|
82
|
+
/** Coded slice segment of a RASL picture */
|
83
|
+
RASL_R = 9,
|
84
|
+
|
85
|
+
// 10-15 reserved
|
86
|
+
|
87
|
+
/** Coded slice segment of a BLA picture */
|
88
|
+
BLA_W_LP = 16,
|
89
|
+
/** Coded slice segment of a BLA picture */
|
90
|
+
BLA_W_RADL = 17,
|
91
|
+
/** Coded slice segment of a BLA picture */
|
92
|
+
BLA_N_LP = 18,
|
93
|
+
/** Coded slice segment of an IDR picture */
|
94
|
+
IDR_W_RADL = 19,
|
95
|
+
/** Coded slice segment of an IDR picture */
|
96
|
+
IDR_N_LP = 20,
|
97
|
+
/** Coded slice segment of a CRA picture */
|
98
|
+
CRA_NUT = 21,
|
99
|
+
|
100
|
+
// 22-31 reserved
|
101
|
+
|
102
|
+
/** Video parameter set */
|
103
|
+
VPS_NUT = 32,
|
104
|
+
/** Sequence parameter set */
|
105
|
+
SPS_NUT = 33,
|
106
|
+
/** Picture parameter set */
|
107
|
+
PPS_NUT = 34,
|
108
|
+
/** Access unit delimiter */
|
109
|
+
AUD_NUT = 35,
|
110
|
+
/** End of sequence */
|
111
|
+
EOS_NUT = 36,
|
112
|
+
/** End of bitstream */
|
113
|
+
EOB_NUT = 37,
|
114
|
+
/** Filler data */
|
115
|
+
FD_NUT = 38,
|
116
|
+
/** Supplemental enhancement information */
|
117
|
+
PREFIX_SEI_NUT = 39,
|
118
|
+
/** Supplemental enhancement information */
|
119
|
+
SUFFIX_SEI_NUT = 40,
|
120
|
+
|
121
|
+
// 41-47 reserved
|
122
|
+
// 48-63 unspecified
|
123
|
+
}
|
124
|
+
|
125
|
+
/**
|
126
|
+
* Parse H.264 NALU type from the first byte of a NALU
|
127
|
+
* @param startByte First byte of the NALU
|
128
|
+
* @returns H.264 NALU type
|
129
|
+
*/
|
130
|
+
function parseH264NALUType(startByte: number): H264NALUType {
|
131
|
+
return startByte & kH264NaluTypeMask;
|
132
|
+
}
|
133
|
+
|
134
|
+
/**
|
135
|
+
* Parse H.265 NALU type from the first byte of a NALU
|
136
|
+
* @param firstByte First byte of the NALU
|
137
|
+
* @returns H.265 NALU type
|
138
|
+
*/
|
139
|
+
function parseH265NALUType(firstByte: number): H265NALUType {
|
140
|
+
// In H.265, NALU type is in bits 1-6 (shifted right by 1)
|
141
|
+
return (firstByte >> 1) & 0x3f;
|
142
|
+
}
|
143
|
+
|
144
|
+
/**
|
145
|
+
* Check if H.264 NALU type is a slice (IDR or non-IDR)
|
146
|
+
* @param naluType H.264 NALU type
|
147
|
+
* @returns True if the NALU is a slice
|
148
|
+
*/
|
149
|
+
function isH264SliceNALU(naluType: H264NALUType): boolean {
|
150
|
+
return naluType === H264NALUType.SLICE_IDR || naluType === H264NALUType.SLICE_NON_IDR;
|
151
|
+
}
|
152
|
+
|
153
|
+
/**
|
154
|
+
* Check if H.265 NALU type is a slice
|
155
|
+
* @param naluType H.265 NALU type
|
156
|
+
* @returns True if the NALU is a slice
|
157
|
+
*/
|
158
|
+
function isH265SliceNALU(naluType: H265NALUType): boolean {
|
159
|
+
return (
|
160
|
+
// VCL NALUs (Video Coding Layer) - slice segments
|
161
|
+
naluType === H265NALUType.TRAIL_N ||
|
162
|
+
naluType === H265NALUType.TRAIL_R ||
|
163
|
+
naluType === H265NALUType.TSA_N ||
|
164
|
+
naluType === H265NALUType.TSA_R ||
|
165
|
+
naluType === H265NALUType.STSA_N ||
|
166
|
+
naluType === H265NALUType.STSA_R ||
|
167
|
+
naluType === H265NALUType.RADL_N ||
|
168
|
+
naluType === H265NALUType.RADL_R ||
|
169
|
+
naluType === H265NALUType.RASL_N ||
|
170
|
+
naluType === H265NALUType.RASL_R ||
|
171
|
+
naluType === H265NALUType.BLA_W_LP ||
|
172
|
+
naluType === H265NALUType.BLA_W_RADL ||
|
173
|
+
naluType === H265NALUType.BLA_N_LP ||
|
174
|
+
naluType === H265NALUType.IDR_W_RADL ||
|
175
|
+
naluType === H265NALUType.IDR_N_LP ||
|
176
|
+
naluType === H265NALUType.CRA_NUT
|
177
|
+
);
|
178
|
+
}
|
179
|
+
|
180
|
+
/**
|
181
|
+
* Detected codec type from NALU analysis
|
182
|
+
*/
|
183
|
+
export type DetectedCodec = 'h264' | 'h265' | 'unknown';
|
184
|
+
|
185
|
+
/**
|
186
|
+
* Result of NALU processing for frame encryption
|
187
|
+
*/
|
188
|
+
export interface NALUProcessingResult {
|
189
|
+
/** Number of unencrypted bytes at the start of the frame */
|
190
|
+
unencryptedBytes: number;
|
191
|
+
/** Detected codec type */
|
192
|
+
detectedCodec: DetectedCodec;
|
193
|
+
/** Whether this frame requires NALU processing */
|
194
|
+
requiresNALUProcessing: boolean;
|
195
|
+
}
|
196
|
+
|
197
|
+
/**
|
198
|
+
* Detect codec type by examining NALU types in the data
|
199
|
+
* @param data Frame data
|
200
|
+
* @param naluIndices Indices where NALUs start
|
201
|
+
* @returns Detected codec type
|
202
|
+
*/
|
203
|
+
function detectCodecFromNALUs(data: Uint8Array, naluIndices: number[]): DetectedCodec {
|
204
|
+
for (const naluIndex of naluIndices) {
|
205
|
+
if (isH264SliceNALU(parseH264NALUType(data[naluIndex]))) return 'h264';
|
206
|
+
if (isH265SliceNALU(parseH265NALUType(data[naluIndex]))) return 'h265';
|
207
|
+
}
|
208
|
+
return 'unknown';
|
209
|
+
}
|
210
|
+
|
211
|
+
/**
|
212
|
+
* Find the first slice NALU and return the number of unencrypted bytes
|
213
|
+
* @param data Frame data
|
214
|
+
* @param naluIndices Indices where NALUs start
|
215
|
+
* @param codec Codec type to use for parsing
|
216
|
+
* @returns Number of unencrypted bytes (index + 2) or null if no slice found
|
217
|
+
*/
|
218
|
+
function findSliceNALUUnencryptedBytes(
|
219
|
+
data: Uint8Array,
|
220
|
+
naluIndices: number[],
|
221
|
+
codec: 'h264' | 'h265',
|
222
|
+
): number | null {
|
223
|
+
for (const index of naluIndices) {
|
224
|
+
if (codec === 'h265') {
|
225
|
+
const type = parseH265NALUType(data[index]);
|
226
|
+
if (isH265SliceNALU(type)) {
|
227
|
+
return index + 2;
|
228
|
+
}
|
229
|
+
} else {
|
230
|
+
const type = parseH264NALUType(data[index]);
|
231
|
+
if (isH264SliceNALU(type)) {
|
232
|
+
return index + 2;
|
233
|
+
}
|
234
|
+
}
|
235
|
+
}
|
236
|
+
return null;
|
237
|
+
}
|
238
|
+
|
239
|
+
/**
|
240
|
+
* Find all NALU start indices in a byte stream
|
241
|
+
* Supports both H.264 and H.265 with 3-byte and 4-byte start codes
|
242
|
+
*
|
243
|
+
* This function slices the NALUs present in the supplied buffer, assuming it is already byte-aligned.
|
244
|
+
* Code adapted from https://github.com/medooze/h264-frame-parser/blob/main/lib/NalUnits.ts to return indices only
|
245
|
+
*
|
246
|
+
* @param stream Byte stream containing NALUs
|
247
|
+
* @returns Array of indices where NALUs start (after the start code)
|
248
|
+
*/
|
249
|
+
function findNALUIndices(stream: Uint8Array): number[] {
|
250
|
+
const result: number[] = [];
|
251
|
+
let start = 0,
|
252
|
+
pos = 0,
|
253
|
+
searchLength = stream.length - 3; // Changed to -3 to handle 4-byte start codes
|
254
|
+
|
255
|
+
while (pos < searchLength) {
|
256
|
+
// skip until end of current NALU - check for both 3-byte and 4-byte start codes
|
257
|
+
while (pos < searchLength) {
|
258
|
+
// Check for 4-byte start code: 0x00 0x00 0x00 0x01
|
259
|
+
if (
|
260
|
+
pos < searchLength - 1 &&
|
261
|
+
stream[pos] === 0 &&
|
262
|
+
stream[pos + 1] === 0 &&
|
263
|
+
stream[pos + 2] === 0 &&
|
264
|
+
stream[pos + 3] === 1
|
265
|
+
) {
|
266
|
+
break;
|
267
|
+
}
|
268
|
+
// Check for 3-byte start code: 0x00 0x00 0x01
|
269
|
+
if (stream[pos] === 0 && stream[pos + 1] === 0 && stream[pos + 2] === 1) {
|
270
|
+
break;
|
271
|
+
}
|
272
|
+
pos++;
|
273
|
+
}
|
274
|
+
|
275
|
+
if (pos >= searchLength) pos = stream.length;
|
276
|
+
|
277
|
+
// remove trailing zeros from current NALU
|
278
|
+
let end = pos;
|
279
|
+
while (end > start && stream[end - 1] === 0) end--;
|
280
|
+
|
281
|
+
// save current NALU
|
282
|
+
if (start === 0) {
|
283
|
+
if (end !== start) throw TypeError('byte stream contains leading data');
|
284
|
+
} else {
|
285
|
+
result.push(start);
|
286
|
+
}
|
287
|
+
|
288
|
+
// begin new NALU - determine start code length
|
289
|
+
let startCodeLength = 3;
|
290
|
+
if (
|
291
|
+
pos < stream.length - 3 &&
|
292
|
+
stream[pos] === 0 &&
|
293
|
+
stream[pos + 1] === 0 &&
|
294
|
+
stream[pos + 2] === 0 &&
|
295
|
+
stream[pos + 3] === 1
|
296
|
+
) {
|
297
|
+
startCodeLength = 4;
|
298
|
+
}
|
299
|
+
|
300
|
+
start = pos = pos + startCodeLength;
|
301
|
+
}
|
302
|
+
return result;
|
303
|
+
}
|
304
|
+
|
305
|
+
/**
|
306
|
+
* Process NALU data for frame encryption, detecting codec and finding unencrypted bytes
|
307
|
+
* @param data Frame data
|
308
|
+
* @param knownCodec Known codec from other sources (optional)
|
309
|
+
* @returns NALU processing result
|
310
|
+
*/
|
311
|
+
export function processNALUsForEncryption(
|
312
|
+
data: Uint8Array,
|
313
|
+
knownCodec?: 'h264' | 'h265',
|
314
|
+
): NALUProcessingResult {
|
315
|
+
const naluIndices = findNALUIndices(data);
|
316
|
+
const detectedCodec = knownCodec ?? detectCodecFromNALUs(data, naluIndices);
|
317
|
+
|
318
|
+
if (detectedCodec === 'unknown') {
|
319
|
+
return { unencryptedBytes: 0, detectedCodec, requiresNALUProcessing: false };
|
320
|
+
}
|
321
|
+
|
322
|
+
const unencryptedBytes = findSliceNALUUnencryptedBytes(data, naluIndices, detectedCodec);
|
323
|
+
if (unencryptedBytes === null) {
|
324
|
+
throw new TypeError('Could not find NALU');
|
325
|
+
}
|
326
|
+
|
327
|
+
return { unencryptedBytes, detectedCodec, requiresNALUProcessing: true };
|
328
|
+
}
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import type { VideoCodec } from '../..';
|
2
|
+
|
3
|
+
// Payload definitions taken from https://github.com/livekit/livekit/blob/master/pkg/sfu/downtrack.go#L104
|
4
|
+
|
5
|
+
export const VP8KeyFrame8x8 = new Uint8Array([
|
6
|
+
0x10, 0x02, 0x00, 0x9d, 0x01, 0x2a, 0x08, 0x00, 0x08, 0x00, 0x00, 0x47, 0x08, 0x85, 0x85, 0x88,
|
7
|
+
0x85, 0x84, 0x88, 0x02, 0x02, 0x00, 0x0c, 0x0d, 0x60, 0x00, 0xfe, 0xff, 0xab, 0x50, 0x80,
|
8
|
+
]);
|
9
|
+
|
10
|
+
export const H264KeyFrame2x2SPS = new Uint8Array([
|
11
|
+
0x67, 0x42, 0xc0, 0x1f, 0x0f, 0xd9, 0x1f, 0x88, 0x88, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00,
|
12
|
+
0x00, 0x03, 0x00, 0xc8, 0x3c, 0x60, 0xc9, 0x20,
|
13
|
+
]);
|
14
|
+
|
15
|
+
export const H264KeyFrame2x2PPS = new Uint8Array([0x68, 0x87, 0xcb, 0x83, 0xcb, 0x20]);
|
16
|
+
|
17
|
+
export const H264KeyFrame2x2IDR = new Uint8Array([
|
18
|
+
0x65, 0x88, 0x84, 0x0a, 0xf2, 0x62, 0x80, 0x00, 0xa7, 0xbe,
|
19
|
+
]);
|
20
|
+
|
21
|
+
export const H264KeyFrame2x2 = [H264KeyFrame2x2SPS, H264KeyFrame2x2PPS, H264KeyFrame2x2IDR];
|
22
|
+
|
23
|
+
export const OpusSilenceFrame = new Uint8Array([
|
24
|
+
0xf8, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
25
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
26
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
27
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
28
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
29
|
+
]);
|
30
|
+
|
31
|
+
/**
|
32
|
+
* Create a crypto hash using Web Crypto API for secure comparison operations
|
33
|
+
*/
|
34
|
+
async function cryptoHash(data: Uint8Array | ArrayBuffer): Promise<string> {
|
35
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
36
|
+
const hashArray = new Uint8Array(hashBuffer);
|
37
|
+
return Array.from(hashArray)
|
38
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
39
|
+
.join('');
|
40
|
+
}
|
41
|
+
|
42
|
+
/**
|
43
|
+
* Pre-computed SHA-256 hashes for secure comparison operations
|
44
|
+
*/
|
45
|
+
export const CryptoHashes = {
|
46
|
+
VP8KeyFrame8x8: 'ef0161653d8b2b23aad46624b420af1d03ce48950e9fc85718028f91b50f9219',
|
47
|
+
H264KeyFrame2x2SPS: 'f0a0e09647d891d6d50aa898bce7108090375d0d55e50a2bb21147afee558e44',
|
48
|
+
H264KeyFrame2x2PPS: '61d9665eed71b6d424ae9539330a3bdd5cb386d4d781c808219a6e36750493a7',
|
49
|
+
H264KeyFrame2x2IDR: 'faffc26b68a2fc09096fa20f3351e706398b6f838a7500c8063472c2e476e90d',
|
50
|
+
OpusSilenceFrame: 'aad8d31fc56b2802ca500e58c2fb9d0b29ad71bb7cb52cd6530251eade188988',
|
51
|
+
} as const;
|
52
|
+
|
53
|
+
/**
|
54
|
+
* Check if a byte array matches any of the known SIF payload frame types using secure crypto hashes
|
55
|
+
*/
|
56
|
+
export async function identifySifPayload(
|
57
|
+
data: Uint8Array | ArrayBuffer,
|
58
|
+
): Promise<VideoCodec | 'opus' | null> {
|
59
|
+
const hash = await cryptoHash(data);
|
60
|
+
|
61
|
+
switch (hash) {
|
62
|
+
case CryptoHashes.VP8KeyFrame8x8:
|
63
|
+
return 'vp8';
|
64
|
+
case CryptoHashes.H264KeyFrame2x2SPS:
|
65
|
+
return 'h264';
|
66
|
+
case CryptoHashes.H264KeyFrame2x2PPS:
|
67
|
+
return 'h264';
|
68
|
+
case CryptoHashes.H264KeyFrame2x2IDR:
|
69
|
+
return 'h264';
|
70
|
+
case CryptoHashes.OpusSilenceFrame:
|
71
|
+
return 'opus';
|
72
|
+
default:
|
73
|
+
return null;
|
74
|
+
}
|
75
|
+
}
|
package/src/index.ts
CHANGED
@@ -62,8 +62,8 @@ export { facingModeFromDeviceLabel, facingModeFromLocalTrack } from './room/trac
|
|
62
62
|
export * from './room/track/options';
|
63
63
|
export * from './room/track/processor/types';
|
64
64
|
export * from './room/track/types';
|
65
|
-
export type * from './room/StreamReader';
|
66
|
-
export type * from './room/StreamWriter';
|
65
|
+
export type * from './room/data-stream/incoming/StreamReader';
|
66
|
+
export type * from './room/data-stream/outgoing/StreamWriter';
|
67
67
|
export type {
|
68
68
|
DataPublishOptions,
|
69
69
|
SimulationScenario,
|