livekit-client 2.15.3 → 2.15.5
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/README.md +2 -2
- 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 +329 -124
- package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
- package/dist/livekit-client.esm.mjs +868 -548
- 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/api/SignalClient.d.ts.map +1 -1
- package/dist/src/e2ee/worker/FrameCryptor.d.ts +0 -46
- 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/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/src/room/{StreamReader.d.ts → data-stream/incoming/StreamReader.d.ts} +32 -6
- 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 +33 -20
- package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
- package/dist/src/room/track/LocalTrack.d.ts +8 -2
- package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
- package/dist/src/room/track/record.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/ts4.2/src/e2ee/worker/FrameCryptor.d.ts +0 -46
- package/dist/ts4.2/src/e2ee/worker/naluUtils.d.ts +27 -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/ts4.2/src/room/{StreamReader.d.ts → data-stream/incoming/StreamReader.d.ts} +32 -6
- 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 +33 -20
- package/dist/ts4.2/src/room/track/LocalTrack.d.ts +8 -2
- package/dist/ts4.2/src/room/types.d.ts +17 -1
- package/package.json +1 -1
- package/src/api/SignalClient.ts +6 -0
- package/src/e2ee/worker/FrameCryptor.ts +48 -139
- package/src/e2ee/worker/naluUtils.ts +328 -0
- package/src/index.ts +2 -2
- package/src/room/Room.ts +94 -207
- 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 +48 -299
- package/src/room/track/LocalAudioTrack.ts +2 -2
- package/src/room/track/LocalTrack.ts +75 -49
- package/src/room/track/record.ts +15 -2
- package/src/room/types.ts +22 -1
- package/src/room/utils.ts +3 -3
- package/dist/src/room/StreamReader.d.ts.map +0 -1
- package/dist/src/room/StreamWriter.d.ts.map +0 -1
- package/src/room/StreamReader.ts +0 -170
@@ -503,6 +503,22 @@ var ConnectionErrorReason;
|
|
503
503
|
ConnectionErrorReason[ConnectionErrorReason["LeaveRequest"] = 4] = "LeaveRequest";
|
504
504
|
ConnectionErrorReason[ConnectionErrorReason["Timeout"] = 5] = "Timeout";
|
505
505
|
})(ConnectionErrorReason || (ConnectionErrorReason = {}));
|
506
|
+
// NOTE: matches with https://github.com/livekit/client-sdk-swift/blob/f37bbd260d61e165084962db822c79f995f1a113/Sources/LiveKit/DataStream/StreamError.swift#L17
|
507
|
+
var DataStreamErrorReason;
|
508
|
+
(function (DataStreamErrorReason) {
|
509
|
+
// Unable to open a stream with the same ID more than once.
|
510
|
+
DataStreamErrorReason[DataStreamErrorReason["AlreadyOpened"] = 0] = "AlreadyOpened";
|
511
|
+
// Stream closed abnormally by remote participant.
|
512
|
+
DataStreamErrorReason[DataStreamErrorReason["AbnormalEnd"] = 1] = "AbnormalEnd";
|
513
|
+
// Incoming chunk data could not be decoded.
|
514
|
+
DataStreamErrorReason[DataStreamErrorReason["DecodeFailed"] = 2] = "DecodeFailed";
|
515
|
+
// Read length exceeded total length specified in stream header.
|
516
|
+
DataStreamErrorReason[DataStreamErrorReason["LengthExceeded"] = 3] = "LengthExceeded";
|
517
|
+
// Read length less than total length specified in stream header.
|
518
|
+
DataStreamErrorReason[DataStreamErrorReason["Incomplete"] = 4] = "Incomplete";
|
519
|
+
// Unable to register a stream handler more than once.
|
520
|
+
DataStreamErrorReason[DataStreamErrorReason["HandlerAlreadyRegistered"] = 7] = "HandlerAlreadyRegistered";
|
521
|
+
})(DataStreamErrorReason || (DataStreamErrorReason = {}));
|
506
522
|
var MediaDeviceFailure;
|
507
523
|
(function (MediaDeviceFailure) {
|
508
524
|
// user rejected permissions
|
@@ -1113,6 +1129,266 @@ class SifGuard {
|
|
1113
1129
|
}
|
1114
1130
|
}
|
1115
1131
|
|
1132
|
+
/**
|
1133
|
+
* NALU (Network Abstraction Layer Unit) utilities for H.264 and H.265 video processing
|
1134
|
+
* Contains functions for parsing and working with NALUs in video frames
|
1135
|
+
*/
|
1136
|
+
/**
|
1137
|
+
* Mask for extracting NALU type from H.264 header byte
|
1138
|
+
*/
|
1139
|
+
const kH264NaluTypeMask = 0x1f;
|
1140
|
+
/**
|
1141
|
+
* H.264 NALU types according to RFC 6184
|
1142
|
+
*/
|
1143
|
+
var H264NALUType;
|
1144
|
+
(function (H264NALUType) {
|
1145
|
+
/** Coded slice of a non-IDR picture */
|
1146
|
+
H264NALUType[H264NALUType["SLICE_NON_IDR"] = 1] = "SLICE_NON_IDR";
|
1147
|
+
/** Coded slice data partition A */
|
1148
|
+
H264NALUType[H264NALUType["SLICE_PARTITION_A"] = 2] = "SLICE_PARTITION_A";
|
1149
|
+
/** Coded slice data partition B */
|
1150
|
+
H264NALUType[H264NALUType["SLICE_PARTITION_B"] = 3] = "SLICE_PARTITION_B";
|
1151
|
+
/** Coded slice data partition C */
|
1152
|
+
H264NALUType[H264NALUType["SLICE_PARTITION_C"] = 4] = "SLICE_PARTITION_C";
|
1153
|
+
/** Coded slice of an IDR picture */
|
1154
|
+
H264NALUType[H264NALUType["SLICE_IDR"] = 5] = "SLICE_IDR";
|
1155
|
+
/** Supplemental enhancement information */
|
1156
|
+
H264NALUType[H264NALUType["SEI"] = 6] = "SEI";
|
1157
|
+
/** Sequence parameter set */
|
1158
|
+
H264NALUType[H264NALUType["SPS"] = 7] = "SPS";
|
1159
|
+
/** Picture parameter set */
|
1160
|
+
H264NALUType[H264NALUType["PPS"] = 8] = "PPS";
|
1161
|
+
/** Access unit delimiter */
|
1162
|
+
H264NALUType[H264NALUType["AUD"] = 9] = "AUD";
|
1163
|
+
/** End of sequence */
|
1164
|
+
H264NALUType[H264NALUType["END_SEQ"] = 10] = "END_SEQ";
|
1165
|
+
/** End of stream */
|
1166
|
+
H264NALUType[H264NALUType["END_STREAM"] = 11] = "END_STREAM";
|
1167
|
+
/** Filler data */
|
1168
|
+
H264NALUType[H264NALUType["FILLER_DATA"] = 12] = "FILLER_DATA";
|
1169
|
+
/** Sequence parameter set extension */
|
1170
|
+
H264NALUType[H264NALUType["SPS_EXT"] = 13] = "SPS_EXT";
|
1171
|
+
/** Prefix NAL unit */
|
1172
|
+
H264NALUType[H264NALUType["PREFIX_NALU"] = 14] = "PREFIX_NALU";
|
1173
|
+
/** Subset sequence parameter set */
|
1174
|
+
H264NALUType[H264NALUType["SUBSET_SPS"] = 15] = "SUBSET_SPS";
|
1175
|
+
/** Depth parameter set */
|
1176
|
+
H264NALUType[H264NALUType["DPS"] = 16] = "DPS";
|
1177
|
+
// 17, 18 reserved
|
1178
|
+
/** Coded slice of an auxiliary coded picture without partitioning */
|
1179
|
+
H264NALUType[H264NALUType["SLICE_AUX"] = 19] = "SLICE_AUX";
|
1180
|
+
/** Coded slice extension */
|
1181
|
+
H264NALUType[H264NALUType["SLICE_EXT"] = 20] = "SLICE_EXT";
|
1182
|
+
/** Coded slice extension for a depth view component or a 3D-AVC texture view component */
|
1183
|
+
H264NALUType[H264NALUType["SLICE_LAYER_EXT"] = 21] = "SLICE_LAYER_EXT";
|
1184
|
+
// 22, 23 reserved
|
1185
|
+
})(H264NALUType || (H264NALUType = {}));
|
1186
|
+
/**
|
1187
|
+
* H.265/HEVC NALU types according to ITU-T H.265
|
1188
|
+
*/
|
1189
|
+
var H265NALUType;
|
1190
|
+
(function (H265NALUType) {
|
1191
|
+
/** Coded slice segment of a non-TSA, non-STSA trailing picture */
|
1192
|
+
H265NALUType[H265NALUType["TRAIL_N"] = 0] = "TRAIL_N";
|
1193
|
+
/** Coded slice segment of a non-TSA, non-STSA trailing picture */
|
1194
|
+
H265NALUType[H265NALUType["TRAIL_R"] = 1] = "TRAIL_R";
|
1195
|
+
/** Coded slice segment of a TSA picture */
|
1196
|
+
H265NALUType[H265NALUType["TSA_N"] = 2] = "TSA_N";
|
1197
|
+
/** Coded slice segment of a TSA picture */
|
1198
|
+
H265NALUType[H265NALUType["TSA_R"] = 3] = "TSA_R";
|
1199
|
+
/** Coded slice segment of an STSA picture */
|
1200
|
+
H265NALUType[H265NALUType["STSA_N"] = 4] = "STSA_N";
|
1201
|
+
/** Coded slice segment of an STSA picture */
|
1202
|
+
H265NALUType[H265NALUType["STSA_R"] = 5] = "STSA_R";
|
1203
|
+
/** Coded slice segment of a RADL picture */
|
1204
|
+
H265NALUType[H265NALUType["RADL_N"] = 6] = "RADL_N";
|
1205
|
+
/** Coded slice segment of a RADL picture */
|
1206
|
+
H265NALUType[H265NALUType["RADL_R"] = 7] = "RADL_R";
|
1207
|
+
/** Coded slice segment of a RASL picture */
|
1208
|
+
H265NALUType[H265NALUType["RASL_N"] = 8] = "RASL_N";
|
1209
|
+
/** Coded slice segment of a RASL picture */
|
1210
|
+
H265NALUType[H265NALUType["RASL_R"] = 9] = "RASL_R";
|
1211
|
+
// 10-15 reserved
|
1212
|
+
/** Coded slice segment of a BLA picture */
|
1213
|
+
H265NALUType[H265NALUType["BLA_W_LP"] = 16] = "BLA_W_LP";
|
1214
|
+
/** Coded slice segment of a BLA picture */
|
1215
|
+
H265NALUType[H265NALUType["BLA_W_RADL"] = 17] = "BLA_W_RADL";
|
1216
|
+
/** Coded slice segment of a BLA picture */
|
1217
|
+
H265NALUType[H265NALUType["BLA_N_LP"] = 18] = "BLA_N_LP";
|
1218
|
+
/** Coded slice segment of an IDR picture */
|
1219
|
+
H265NALUType[H265NALUType["IDR_W_RADL"] = 19] = "IDR_W_RADL";
|
1220
|
+
/** Coded slice segment of an IDR picture */
|
1221
|
+
H265NALUType[H265NALUType["IDR_N_LP"] = 20] = "IDR_N_LP";
|
1222
|
+
/** Coded slice segment of a CRA picture */
|
1223
|
+
H265NALUType[H265NALUType["CRA_NUT"] = 21] = "CRA_NUT";
|
1224
|
+
// 22-31 reserved
|
1225
|
+
/** Video parameter set */
|
1226
|
+
H265NALUType[H265NALUType["VPS_NUT"] = 32] = "VPS_NUT";
|
1227
|
+
/** Sequence parameter set */
|
1228
|
+
H265NALUType[H265NALUType["SPS_NUT"] = 33] = "SPS_NUT";
|
1229
|
+
/** Picture parameter set */
|
1230
|
+
H265NALUType[H265NALUType["PPS_NUT"] = 34] = "PPS_NUT";
|
1231
|
+
/** Access unit delimiter */
|
1232
|
+
H265NALUType[H265NALUType["AUD_NUT"] = 35] = "AUD_NUT";
|
1233
|
+
/** End of sequence */
|
1234
|
+
H265NALUType[H265NALUType["EOS_NUT"] = 36] = "EOS_NUT";
|
1235
|
+
/** End of bitstream */
|
1236
|
+
H265NALUType[H265NALUType["EOB_NUT"] = 37] = "EOB_NUT";
|
1237
|
+
/** Filler data */
|
1238
|
+
H265NALUType[H265NALUType["FD_NUT"] = 38] = "FD_NUT";
|
1239
|
+
/** Supplemental enhancement information */
|
1240
|
+
H265NALUType[H265NALUType["PREFIX_SEI_NUT"] = 39] = "PREFIX_SEI_NUT";
|
1241
|
+
/** Supplemental enhancement information */
|
1242
|
+
H265NALUType[H265NALUType["SUFFIX_SEI_NUT"] = 40] = "SUFFIX_SEI_NUT";
|
1243
|
+
// 41-47 reserved
|
1244
|
+
// 48-63 unspecified
|
1245
|
+
})(H265NALUType || (H265NALUType = {}));
|
1246
|
+
/**
|
1247
|
+
* Parse H.264 NALU type from the first byte of a NALU
|
1248
|
+
* @param startByte First byte of the NALU
|
1249
|
+
* @returns H.264 NALU type
|
1250
|
+
*/
|
1251
|
+
function parseH264NALUType(startByte) {
|
1252
|
+
return startByte & kH264NaluTypeMask;
|
1253
|
+
}
|
1254
|
+
/**
|
1255
|
+
* Parse H.265 NALU type from the first byte of a NALU
|
1256
|
+
* @param firstByte First byte of the NALU
|
1257
|
+
* @returns H.265 NALU type
|
1258
|
+
*/
|
1259
|
+
function parseH265NALUType(firstByte) {
|
1260
|
+
// In H.265, NALU type is in bits 1-6 (shifted right by 1)
|
1261
|
+
return firstByte >> 1 & 0x3f;
|
1262
|
+
}
|
1263
|
+
/**
|
1264
|
+
* Check if H.264 NALU type is a slice (IDR or non-IDR)
|
1265
|
+
* @param naluType H.264 NALU type
|
1266
|
+
* @returns True if the NALU is a slice
|
1267
|
+
*/
|
1268
|
+
function isH264SliceNALU(naluType) {
|
1269
|
+
return naluType === H264NALUType.SLICE_IDR || naluType === H264NALUType.SLICE_NON_IDR;
|
1270
|
+
}
|
1271
|
+
/**
|
1272
|
+
* Check if H.265 NALU type is a slice
|
1273
|
+
* @param naluType H.265 NALU type
|
1274
|
+
* @returns True if the NALU is a slice
|
1275
|
+
*/
|
1276
|
+
function isH265SliceNALU(naluType) {
|
1277
|
+
return (
|
1278
|
+
// VCL NALUs (Video Coding Layer) - slice segments
|
1279
|
+
naluType === H265NALUType.TRAIL_N || naluType === H265NALUType.TRAIL_R || naluType === H265NALUType.TSA_N || naluType === H265NALUType.TSA_R || naluType === H265NALUType.STSA_N || naluType === H265NALUType.STSA_R || naluType === H265NALUType.RADL_N || naluType === H265NALUType.RADL_R || naluType === H265NALUType.RASL_N || naluType === H265NALUType.RASL_R || naluType === H265NALUType.BLA_W_LP || naluType === H265NALUType.BLA_W_RADL || naluType === H265NALUType.BLA_N_LP || naluType === H265NALUType.IDR_W_RADL || naluType === H265NALUType.IDR_N_LP || naluType === H265NALUType.CRA_NUT
|
1280
|
+
);
|
1281
|
+
}
|
1282
|
+
/**
|
1283
|
+
* Detect codec type by examining NALU types in the data
|
1284
|
+
* @param data Frame data
|
1285
|
+
* @param naluIndices Indices where NALUs start
|
1286
|
+
* @returns Detected codec type
|
1287
|
+
*/
|
1288
|
+
function detectCodecFromNALUs(data, naluIndices) {
|
1289
|
+
for (const naluIndex of naluIndices) {
|
1290
|
+
if (isH264SliceNALU(parseH264NALUType(data[naluIndex]))) return 'h264';
|
1291
|
+
if (isH265SliceNALU(parseH265NALUType(data[naluIndex]))) return 'h265';
|
1292
|
+
}
|
1293
|
+
return 'unknown';
|
1294
|
+
}
|
1295
|
+
/**
|
1296
|
+
* Find the first slice NALU and return the number of unencrypted bytes
|
1297
|
+
* @param data Frame data
|
1298
|
+
* @param naluIndices Indices where NALUs start
|
1299
|
+
* @param codec Codec type to use for parsing
|
1300
|
+
* @returns Number of unencrypted bytes (index + 2) or null if no slice found
|
1301
|
+
*/
|
1302
|
+
function findSliceNALUUnencryptedBytes(data, naluIndices, codec) {
|
1303
|
+
for (const index of naluIndices) {
|
1304
|
+
if (codec === 'h265') {
|
1305
|
+
const type = parseH265NALUType(data[index]);
|
1306
|
+
if (isH265SliceNALU(type)) {
|
1307
|
+
return index + 2;
|
1308
|
+
}
|
1309
|
+
} else {
|
1310
|
+
const type = parseH264NALUType(data[index]);
|
1311
|
+
if (isH264SliceNALU(type)) {
|
1312
|
+
return index + 2;
|
1313
|
+
}
|
1314
|
+
}
|
1315
|
+
}
|
1316
|
+
return null;
|
1317
|
+
}
|
1318
|
+
/**
|
1319
|
+
* Find all NALU start indices in a byte stream
|
1320
|
+
* Supports both H.264 and H.265 with 3-byte and 4-byte start codes
|
1321
|
+
*
|
1322
|
+
* This function slices the NALUs present in the supplied buffer, assuming it is already byte-aligned.
|
1323
|
+
* Code adapted from https://github.com/medooze/h264-frame-parser/blob/main/lib/NalUnits.ts to return indices only
|
1324
|
+
*
|
1325
|
+
* @param stream Byte stream containing NALUs
|
1326
|
+
* @returns Array of indices where NALUs start (after the start code)
|
1327
|
+
*/
|
1328
|
+
function findNALUIndices(stream) {
|
1329
|
+
const result = [];
|
1330
|
+
let start = 0,
|
1331
|
+
pos = 0,
|
1332
|
+
searchLength = stream.length - 3; // Changed to -3 to handle 4-byte start codes
|
1333
|
+
while (pos < searchLength) {
|
1334
|
+
// skip until end of current NALU - check for both 3-byte and 4-byte start codes
|
1335
|
+
while (pos < searchLength) {
|
1336
|
+
// Check for 4-byte start code: 0x00 0x00 0x00 0x01
|
1337
|
+
if (pos < searchLength - 1 && stream[pos] === 0 && stream[pos + 1] === 0 && stream[pos + 2] === 0 && stream[pos + 3] === 1) {
|
1338
|
+
break;
|
1339
|
+
}
|
1340
|
+
// Check for 3-byte start code: 0x00 0x00 0x01
|
1341
|
+
if (stream[pos] === 0 && stream[pos + 1] === 0 && stream[pos + 2] === 1) {
|
1342
|
+
break;
|
1343
|
+
}
|
1344
|
+
pos++;
|
1345
|
+
}
|
1346
|
+
if (pos >= searchLength) pos = stream.length;
|
1347
|
+
// remove trailing zeros from current NALU
|
1348
|
+
let end = pos;
|
1349
|
+
while (end > start && stream[end - 1] === 0) end--;
|
1350
|
+
// save current NALU
|
1351
|
+
if (start === 0) {
|
1352
|
+
if (end !== start) throw TypeError('byte stream contains leading data');
|
1353
|
+
} else {
|
1354
|
+
result.push(start);
|
1355
|
+
}
|
1356
|
+
// begin new NALU - determine start code length
|
1357
|
+
let startCodeLength = 3;
|
1358
|
+
if (pos < stream.length - 3 && stream[pos] === 0 && stream[pos + 1] === 0 && stream[pos + 2] === 0 && stream[pos + 3] === 1) {
|
1359
|
+
startCodeLength = 4;
|
1360
|
+
}
|
1361
|
+
start = pos = pos + startCodeLength;
|
1362
|
+
}
|
1363
|
+
return result;
|
1364
|
+
}
|
1365
|
+
/**
|
1366
|
+
* Process NALU data for frame encryption, detecting codec and finding unencrypted bytes
|
1367
|
+
* @param data Frame data
|
1368
|
+
* @param knownCodec Known codec from other sources (optional)
|
1369
|
+
* @returns NALU processing result
|
1370
|
+
*/
|
1371
|
+
function processNALUsForEncryption(data, knownCodec) {
|
1372
|
+
const naluIndices = findNALUIndices(data);
|
1373
|
+
const detectedCodec = knownCodec !== null && knownCodec !== void 0 ? knownCodec : detectCodecFromNALUs(data, naluIndices);
|
1374
|
+
if (detectedCodec === 'unknown') {
|
1375
|
+
return {
|
1376
|
+
unencryptedBytes: 0,
|
1377
|
+
detectedCodec,
|
1378
|
+
requiresNALUProcessing: false
|
1379
|
+
};
|
1380
|
+
}
|
1381
|
+
const unencryptedBytes = findSliceNALUUnencryptedBytes(data, naluIndices, detectedCodec);
|
1382
|
+
if (unencryptedBytes === null) {
|
1383
|
+
throw new TypeError('Could not find NALU');
|
1384
|
+
}
|
1385
|
+
return {
|
1386
|
+
unencryptedBytes,
|
1387
|
+
detectedCodec,
|
1388
|
+
requiresNALUProcessing: true
|
1389
|
+
};
|
1390
|
+
}
|
1391
|
+
|
1116
1392
|
const encryptionEnabledMap = new Map();
|
1117
1393
|
class BaseFrameCryptor extends eventsExports.EventEmitter {
|
1118
1394
|
encodeFunction(encodedFrame, controller) {
|
@@ -1294,7 +1570,7 @@ class FrameCryptor extends BaseFrameCryptor {
|
|
1294
1570
|
newDataWithoutHeader.set(new Uint8Array(cipherText)); // add ciphertext.
|
1295
1571
|
newDataWithoutHeader.set(new Uint8Array(iv), cipherText.byteLength); // append IV.
|
1296
1572
|
newDataWithoutHeader.set(frameTrailer, cipherText.byteLength + iv.byteLength); // append frame trailer.
|
1297
|
-
if (frameInfo.
|
1573
|
+
if (frameInfo.requiresNALUProcessing) {
|
1298
1574
|
newDataWithoutHeader = writeRbsp(newDataWithoutHeader);
|
1299
1575
|
}
|
1300
1576
|
var newData = new Uint8Array(frameHeader.byteLength + newDataWithoutHeader.byteLength);
|
@@ -1402,7 +1678,7 @@ class FrameCryptor extends BaseFrameCryptor {
|
|
1402
1678
|
try {
|
1403
1679
|
const frameHeader = new Uint8Array(encodedFrame.data, 0, frameInfo.unencryptedBytes);
|
1404
1680
|
var encryptedData = new Uint8Array(encodedFrame.data, frameHeader.length, encodedFrame.data.byteLength - frameHeader.length);
|
1405
|
-
if (frameInfo.
|
1681
|
+
if (frameInfo.requiresNALUProcessing && needsRbspUnescaping(encryptedData)) {
|
1406
1682
|
encryptedData = parseRbsp(encryptedData);
|
1407
1683
|
const newUint8 = new Uint8Array(frameHeader.byteLength + encryptedData.byteLength);
|
1408
1684
|
newUint8.set(frameHeader);
|
@@ -1504,56 +1780,59 @@ class FrameCryptor extends BaseFrameCryptor {
|
|
1504
1780
|
}
|
1505
1781
|
getUnencryptedBytes(frame) {
|
1506
1782
|
var _a;
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1514
|
-
|
1515
|
-
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
|
1520
|
-
|
1521
|
-
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1539
|
-
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1544
|
-
|
1545
|
-
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
1549
|
-
// no op, we just continue and fallback to vp8
|
1783
|
+
// Handle audio frames
|
1784
|
+
if (!isVideoFrame(frame)) {
|
1785
|
+
return {
|
1786
|
+
unencryptedBytes: UNENCRYPTED_BYTES.audio,
|
1787
|
+
requiresNALUProcessing: false
|
1788
|
+
};
|
1789
|
+
}
|
1790
|
+
// Detect and track codec changes
|
1791
|
+
const detectedCodec = (_a = this.getVideoCodec(frame)) !== null && _a !== void 0 ? _a : this.videoCodec;
|
1792
|
+
if (detectedCodec !== this.detectedCodec) {
|
1793
|
+
workerLogger.debug('detected different codec', Object.assign({
|
1794
|
+
detectedCodec,
|
1795
|
+
oldCodec: this.detectedCodec
|
1796
|
+
}, this.logContext));
|
1797
|
+
this.detectedCodec = detectedCodec;
|
1798
|
+
}
|
1799
|
+
// Check for unsupported codecs
|
1800
|
+
if (detectedCodec === 'av1') {
|
1801
|
+
throw new Error("".concat(detectedCodec, " is not yet supported for end to end encryption"));
|
1802
|
+
}
|
1803
|
+
// Handle VP8/VP9 codecs (no NALU processing needed)
|
1804
|
+
if (detectedCodec === 'vp8') {
|
1805
|
+
return {
|
1806
|
+
unencryptedBytes: UNENCRYPTED_BYTES[frame.type],
|
1807
|
+
requiresNALUProcessing: false
|
1808
|
+
};
|
1809
|
+
}
|
1810
|
+
if (detectedCodec === 'vp9') {
|
1811
|
+
return {
|
1812
|
+
unencryptedBytes: 0,
|
1813
|
+
requiresNALUProcessing: false
|
1814
|
+
};
|
1815
|
+
}
|
1816
|
+
// Try NALU processing for H.264/H.265 codecs
|
1817
|
+
try {
|
1818
|
+
const knownCodec = detectedCodec === 'h264' || detectedCodec === 'h265' ? detectedCodec : undefined;
|
1819
|
+
const naluResult = processNALUsForEncryption(new Uint8Array(frame.data), knownCodec);
|
1820
|
+
if (naluResult.requiresNALUProcessing) {
|
1821
|
+
return {
|
1822
|
+
unencryptedBytes: naluResult.unencryptedBytes,
|
1823
|
+
requiresNALUProcessing: true
|
1824
|
+
};
|
1550
1825
|
}
|
1551
|
-
|
1552
|
-
|
1553
|
-
|
1554
|
-
|
1555
|
-
return frameInfo;
|
1826
|
+
} catch (e) {
|
1827
|
+
workerLogger.debug('NALU processing failed, falling back to VP8 handling', Object.assign({
|
1828
|
+
error: e
|
1829
|
+
}, this.logContext));
|
1556
1830
|
}
|
1831
|
+
// Fallback to VP8 handling
|
1832
|
+
return {
|
1833
|
+
unencryptedBytes: UNENCRYPTED_BYTES[frame.type],
|
1834
|
+
requiresNALUProcessing: false
|
1835
|
+
};
|
1557
1836
|
}
|
1558
1837
|
/**
|
1559
1838
|
* inspects frame payloadtype if available and maps it to the codec specified in rtpMap
|
@@ -1567,80 +1846,6 @@ class FrameCryptor extends BaseFrameCryptor {
|
|
1567
1846
|
return codec;
|
1568
1847
|
}
|
1569
1848
|
}
|
1570
|
-
/**
|
1571
|
-
* Slice the NALUs present in the supplied buffer, assuming it is already byte-aligned
|
1572
|
-
* code adapted from https://github.com/medooze/h264-frame-parser/blob/main/lib/NalUnits.ts to return indices only
|
1573
|
-
*/
|
1574
|
-
function findNALUIndices(stream) {
|
1575
|
-
const result = [];
|
1576
|
-
let start = 0,
|
1577
|
-
pos = 0,
|
1578
|
-
searchLength = stream.length - 2;
|
1579
|
-
while (pos < searchLength) {
|
1580
|
-
// skip until end of current NALU
|
1581
|
-
while (pos < searchLength && !(stream[pos] === 0 && stream[pos + 1] === 0 && stream[pos + 2] === 1)) pos++;
|
1582
|
-
if (pos >= searchLength) pos = stream.length;
|
1583
|
-
// remove trailing zeros from current NALU
|
1584
|
-
let end = pos;
|
1585
|
-
while (end > start && stream[end - 1] === 0) end--;
|
1586
|
-
// save current NALU
|
1587
|
-
if (start === 0) {
|
1588
|
-
if (end !== start) throw TypeError('byte stream contains leading data');
|
1589
|
-
} else {
|
1590
|
-
result.push(start);
|
1591
|
-
}
|
1592
|
-
// begin new NALU
|
1593
|
-
start = pos = pos + 3;
|
1594
|
-
}
|
1595
|
-
return result;
|
1596
|
-
}
|
1597
|
-
function parseNALUType(startByte) {
|
1598
|
-
return startByte & kNaluTypeMask;
|
1599
|
-
}
|
1600
|
-
const kNaluTypeMask = 0x1f;
|
1601
|
-
var NALUType;
|
1602
|
-
(function (NALUType) {
|
1603
|
-
/** Coded slice of a non-IDR picture */
|
1604
|
-
NALUType[NALUType["SLICE_NON_IDR"] = 1] = "SLICE_NON_IDR";
|
1605
|
-
/** Coded slice data partition A */
|
1606
|
-
NALUType[NALUType["SLICE_PARTITION_A"] = 2] = "SLICE_PARTITION_A";
|
1607
|
-
/** Coded slice data partition B */
|
1608
|
-
NALUType[NALUType["SLICE_PARTITION_B"] = 3] = "SLICE_PARTITION_B";
|
1609
|
-
/** Coded slice data partition C */
|
1610
|
-
NALUType[NALUType["SLICE_PARTITION_C"] = 4] = "SLICE_PARTITION_C";
|
1611
|
-
/** Coded slice of an IDR picture */
|
1612
|
-
NALUType[NALUType["SLICE_IDR"] = 5] = "SLICE_IDR";
|
1613
|
-
/** Supplemental enhancement information */
|
1614
|
-
NALUType[NALUType["SEI"] = 6] = "SEI";
|
1615
|
-
/** Sequence parameter set */
|
1616
|
-
NALUType[NALUType["SPS"] = 7] = "SPS";
|
1617
|
-
/** Picture parameter set */
|
1618
|
-
NALUType[NALUType["PPS"] = 8] = "PPS";
|
1619
|
-
/** Access unit delimiter */
|
1620
|
-
NALUType[NALUType["AUD"] = 9] = "AUD";
|
1621
|
-
/** End of sequence */
|
1622
|
-
NALUType[NALUType["END_SEQ"] = 10] = "END_SEQ";
|
1623
|
-
/** End of stream */
|
1624
|
-
NALUType[NALUType["END_STREAM"] = 11] = "END_STREAM";
|
1625
|
-
/** Filler data */
|
1626
|
-
NALUType[NALUType["FILLER_DATA"] = 12] = "FILLER_DATA";
|
1627
|
-
/** Sequence parameter set extension */
|
1628
|
-
NALUType[NALUType["SPS_EXT"] = 13] = "SPS_EXT";
|
1629
|
-
/** Prefix NAL unit */
|
1630
|
-
NALUType[NALUType["PREFIX_NALU"] = 14] = "PREFIX_NALU";
|
1631
|
-
/** Subset sequence parameter set */
|
1632
|
-
NALUType[NALUType["SUBSET_SPS"] = 15] = "SUBSET_SPS";
|
1633
|
-
/** Depth parameter set */
|
1634
|
-
NALUType[NALUType["DPS"] = 16] = "DPS";
|
1635
|
-
// 17, 18 reserved
|
1636
|
-
/** Coded slice of an auxiliary coded picture without partitioning */
|
1637
|
-
NALUType[NALUType["SLICE_AUX"] = 19] = "SLICE_AUX";
|
1638
|
-
/** Coded slice extension */
|
1639
|
-
NALUType[NALUType["SLICE_EXT"] = 20] = "SLICE_EXT";
|
1640
|
-
/** Coded slice extension for a depth view component or a 3D-AVC texture view component */
|
1641
|
-
NALUType[NALUType["SLICE_LAYER_EXT"] = 21] = "SLICE_LAYER_EXT";
|
1642
|
-
// 22, 23 reserved
|
1643
|
-
})(NALUType || (NALUType = {}));
|
1644
1849
|
/**
|
1645
1850
|
* we use a magic frame trailer to detect whether a frame is injected
|
1646
1851
|
* by the livekit server and thus to be treated as unencrypted
|