livekit-client 1.13.3 → 1.13.4

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.
@@ -882,6 +882,54 @@ function ratchet(material, salt) {
882
882
  return crypto.subtle.deriveBits(algorithmOptions, material, 256);
883
883
  });
884
884
  }
885
+ function needsRbspUnescaping(frameData) {
886
+ for (var i = 0; i < frameData.length - 3; i++) {
887
+ if (frameData[i] == 0 && frameData[i + 1] == 0 && frameData[i + 2] == 3) return true;
888
+ }
889
+ return false;
890
+ }
891
+ function parseRbsp(stream) {
892
+ const dataOut = [];
893
+ var length = stream.length;
894
+ for (var i = 0; i < stream.length;) {
895
+ // Be careful about over/underflow here. byte_length_ - 3 can underflow, and
896
+ // i + 3 can overflow, but byte_length_ - i can't, because i < byte_length_
897
+ // above, and that expression will produce the number of bytes left in
898
+ // the stream including the byte at i.
899
+ if (length - i >= 3 && !stream[i] && !stream[i + 1] && stream[i + 2] == 3) {
900
+ // Two rbsp bytes.
901
+ dataOut.push(stream[i++]);
902
+ dataOut.push(stream[i++]);
903
+ // Skip the emulation byte.
904
+ i++;
905
+ } else {
906
+ // Single rbsp byte.
907
+ dataOut.push(stream[i++]);
908
+ }
909
+ }
910
+ return new Uint8Array(dataOut);
911
+ }
912
+ const kZerosInStartSequence = 2;
913
+ const kEmulationByte = 3;
914
+ function writeRbsp(data_in) {
915
+ const dataOut = [];
916
+ var numConsecutiveZeros = 0;
917
+ for (var i = 0; i < data_in.length; ++i) {
918
+ var byte = data_in[i];
919
+ if (byte <= kEmulationByte && numConsecutiveZeros >= kZerosInStartSequence) {
920
+ // Need to escape.
921
+ dataOut.push(kEmulationByte);
922
+ numConsecutiveZeros = 0;
923
+ }
924
+ dataOut.push(byte);
925
+ if (byte == 0) {
926
+ ++numConsecutiveZeros;
927
+ } else {
928
+ numConsecutiveZeros = 0;
929
+ }
930
+ }
931
+ return new Uint8Array(dataOut);
932
+ }
885
933
 
886
934
  class SifGuard {
887
935
  constructor() {
@@ -1045,8 +1093,9 @@ class FrameCryptor extends BaseFrameCryptor {
1045
1093
  const keyIndex = this.keys.getCurrentKeyIndex();
1046
1094
  if (encryptionKey) {
1047
1095
  const iv = this.makeIV((_a = encodedFrame.getMetadata().synchronizationSource) !== null && _a !== void 0 ? _a : -1, encodedFrame.timestamp);
1096
+ let frameInfo = this.getUnencryptedBytes(encodedFrame);
1048
1097
  // Thіs is not encrypted and contains the VP8 payload descriptor or the Opus TOC byte.
1049
- const frameHeader = new Uint8Array(encodedFrame.data, 0, this.getUnencryptedBytes(encodedFrame));
1098
+ const frameHeader = new Uint8Array(encodedFrame.data, 0, frameInfo.unencryptedBytes);
1050
1099
  // Frame trailer contains the R|IV_LENGTH and key index
1051
1100
  const frameTrailer = new Uint8Array(2);
1052
1101
  frameTrailer[0] = IV_LENGTH;
@@ -1063,14 +1112,18 @@ class FrameCryptor extends BaseFrameCryptor {
1063
1112
  name: ENCRYPTION_ALGORITHM,
1064
1113
  iv,
1065
1114
  additionalData: new Uint8Array(encodedFrame.data, 0, frameHeader.byteLength)
1066
- }, encryptionKey, new Uint8Array(encodedFrame.data, this.getUnencryptedBytes(encodedFrame)));
1067
- const newData = new ArrayBuffer(frameHeader.byteLength + cipherText.byteLength + iv.byteLength + frameTrailer.byteLength);
1068
- const newUint8 = new Uint8Array(newData);
1069
- newUint8.set(frameHeader); // copy first bytes.
1070
- newUint8.set(new Uint8Array(cipherText), frameHeader.byteLength); // add ciphertext.
1071
- newUint8.set(new Uint8Array(iv), frameHeader.byteLength + cipherText.byteLength); // append IV.
1072
- newUint8.set(frameTrailer, frameHeader.byteLength + cipherText.byteLength + iv.byteLength); // append frame trailer.
1073
- encodedFrame.data = newData;
1115
+ }, encryptionKey, new Uint8Array(encodedFrame.data, frameInfo.unencryptedBytes));
1116
+ let newDataWithoutHeader = new Uint8Array(cipherText.byteLength + iv.byteLength + frameTrailer.byteLength);
1117
+ newDataWithoutHeader.set(new Uint8Array(cipherText)); // add ciphertext.
1118
+ newDataWithoutHeader.set(new Uint8Array(iv), cipherText.byteLength); // append IV.
1119
+ newDataWithoutHeader.set(frameTrailer, cipherText.byteLength + iv.byteLength); // append frame trailer.
1120
+ if (frameInfo.isH264) {
1121
+ newDataWithoutHeader = writeRbsp(newDataWithoutHeader);
1122
+ }
1123
+ var newData = new Uint8Array(frameHeader.byteLength + newDataWithoutHeader.byteLength);
1124
+ newData.set(frameHeader);
1125
+ newData.set(newDataWithoutHeader, frameHeader.byteLength);
1126
+ encodedFrame.data = newData.buffer;
1074
1127
  return controller.enqueue(encodedFrame);
1075
1128
  } catch (e) {
1076
1129
  // TODO: surface this to the app.
@@ -1150,6 +1203,7 @@ class FrameCryptor extends BaseFrameCryptor {
1150
1203
  if (!ratchetOpts.encryptionKey && !keySet) {
1151
1204
  throw new TypeError("no encryption key found for decryption of ".concat(this.participantIdentity));
1152
1205
  }
1206
+ let frameInfo = this.getUnencryptedBytes(encodedFrame);
1153
1207
  // Construct frame trailer. Similar to the frame header described in
1154
1208
  // https://tools.ietf.org/html/draft-omara-sframe-00#section-4.2
1155
1209
  // but we put it at the end.
@@ -1158,7 +1212,15 @@ class FrameCryptor extends BaseFrameCryptor {
1158
1212
  // payload |IV...(length = IV_LENGTH)|R|IV_LENGTH|KID |
1159
1213
  // ---------+-------------------------+-+---------+----
1160
1214
  try {
1161
- const frameHeader = new Uint8Array(encodedFrame.data, 0, this.getUnencryptedBytes(encodedFrame));
1215
+ const frameHeader = new Uint8Array(encodedFrame.data, 0, frameInfo.unencryptedBytes);
1216
+ var encryptedData = new Uint8Array(encodedFrame.data, frameHeader.length, encodedFrame.data.byteLength - frameHeader.length);
1217
+ if (frameInfo.isH264 && needsRbspUnescaping(encryptedData)) {
1218
+ encryptedData = parseRbsp(encryptedData);
1219
+ const newUint8 = new Uint8Array(frameHeader.byteLength + encryptedData.byteLength);
1220
+ newUint8.set(frameHeader);
1221
+ newUint8.set(encryptedData, frameHeader.byteLength);
1222
+ encodedFrame.data = newUint8.buffer;
1223
+ }
1162
1224
  const frameTrailer = new Uint8Array(encodedFrame.data, encodedFrame.data.byteLength - 2, 2);
1163
1225
  const ivLength = frameTrailer[0];
1164
1226
  const iv = new Uint8Array(encodedFrame.data, encodedFrame.data.byteLength - ivLength - frameTrailer.byteLength, ivLength);
@@ -1253,26 +1315,32 @@ class FrameCryptor extends BaseFrameCryptor {
1253
1315
  }
1254
1316
  getUnencryptedBytes(frame) {
1255
1317
  var _a;
1318
+ var frameInfo = {
1319
+ unencryptedBytes: 0,
1320
+ isH264: false
1321
+ };
1256
1322
  if (isVideoFrame(frame)) {
1257
1323
  let detectedCodec = (_a = this.getVideoCodec(frame)) !== null && _a !== void 0 ? _a : this.videoCodec;
1258
1324
  if (detectedCodec === 'av1' || detectedCodec === 'vp9') {
1259
1325
  throw new Error("".concat(detectedCodec, " is not yet supported for end to end encryption"));
1260
1326
  }
1261
1327
  if (detectedCodec === 'vp8') {
1262
- return UNENCRYPTED_BYTES[frame.type];
1328
+ frameInfo.unencryptedBytes = UNENCRYPTED_BYTES[frame.type];
1329
+ return frameInfo;
1263
1330
  }
1264
1331
  const data = new Uint8Array(frame.data);
1265
1332
  try {
1266
1333
  const naluIndices = findNALUIndices(data);
1267
1334
  // if the detected codec is undefined we test whether it _looks_ like a h264 frame as a best guess
1268
- const isH264 = detectedCodec === 'h264' || naluIndices.some(naluIndex => [NALUType.SLICE_IDR, NALUType.SLICE_NON_IDR].includes(parseNALUType(data[naluIndex])));
1269
- if (isH264) {
1335
+ frameInfo.isH264 = detectedCodec === 'h264' || naluIndices.some(naluIndex => [NALUType.SLICE_IDR, NALUType.SLICE_NON_IDR].includes(parseNALUType(data[naluIndex])));
1336
+ if (frameInfo.isH264) {
1270
1337
  for (const index of naluIndices) {
1271
1338
  let type = parseNALUType(data[index]);
1272
1339
  switch (type) {
1273
1340
  case NALUType.SLICE_IDR:
1274
1341
  case NALUType.SLICE_NON_IDR:
1275
- return index + 2;
1342
+ frameInfo.unencryptedBytes = index + 2;
1343
+ return frameInfo;
1276
1344
  default:
1277
1345
  break;
1278
1346
  }
@@ -1282,9 +1350,11 @@ class FrameCryptor extends BaseFrameCryptor {
1282
1350
  } catch (e) {
1283
1351
  // no op, we just continue and fallback to vp8
1284
1352
  }
1285
- return UNENCRYPTED_BYTES[frame.type];
1353
+ frameInfo.unencryptedBytes = UNENCRYPTED_BYTES[frame.type];
1354
+ return frameInfo;
1286
1355
  } else {
1287
- return UNENCRYPTED_BYTES.audio;
1356
+ frameInfo.unencryptedBytes = UNENCRYPTED_BYTES.audio;
1357
+ return frameInfo;
1288
1358
  }
1289
1359
  }
1290
1360
  /**