Skip to content

Commit 02c2f95

Browse files
authored
feat: Add E2EE support for H265. (#864)
1 parent f7384fb commit 02c2f95

File tree

5 files changed

+427
-109
lines changed

5 files changed

+427
-109
lines changed

lib/src/core/engine.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ class Engine extends Disposable with EventsEmittable<EngineEvent> {
489489
);
490490
}
491491

492-
if (kIsWeb && roomOptions.e2eeOptions != null) {
492+
if (kIsWeb && (roomOptions.e2eeOptions != null || roomOptions.encryption != null)) {
493493
rtcConfiguration = rtcConfiguration.copyWith(encodedInsertableStreams: true);
494494
}
495495

lib/src/extensions.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,12 +266,13 @@ extension DegradationPreferenceExt on DegradationPreference {
266266

267267
extension RoomOptionsEx on RoomOptions {
268268
lk_models.Encryption_Type get lkEncryptionType {
269-
return (e2eeOptions != null)
269+
final e2ee = encryption ?? e2eeOptions;
270+
return (e2ee != null)
270271
? {
271272
EncryptionType.kNone: lk_models.Encryption_Type.NONE,
272273
EncryptionType.kGcm: lk_models.Encryption_Type.GCM,
273274
EncryptionType.kCustom: lk_models.Encryption_Type.CUSTOM,
274-
}[e2eeOptions!.encryptionType]!
275+
}[e2ee.encryptionType]!
275276
: lk_models.Encryption_Type.NONE;
276277
}
277278
}

web/e2ee.frame_cryptor.dart

Lines changed: 19 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -8,99 +8,9 @@ import 'package:web/web.dart' as web;
88
import 'e2ee.keyhandler.dart';
99
import 'e2ee.logger.dart';
1010
import 'e2ee.sfi_guard.dart';
11+
import 'e2ee.nalu_utils.dart';
1112

12-
const kNaluTypeMask = 0x1f;
13-
14-
/// Coded slice of a non-IDR picture
15-
const SLICE_NON_IDR = 1;
16-
17-
/// Coded slice data partition A
18-
const SLICE_PARTITION_A = 2;
19-
20-
/// Coded slice data partition B
21-
const SLICE_PARTITION_B = 3;
22-
23-
/// Coded slice data partition C
24-
const SLICE_PARTITION_C = 4;
25-
26-
/// Coded slice of an IDR picture
27-
const SLICE_IDR = 5;
28-
29-
/// Supplemental enhancement information
30-
const SEI = 6;
31-
32-
/// Sequence parameter set
33-
const SPS = 7;
34-
35-
/// Picture parameter set
36-
const PPS = 8;
37-
38-
/// Access unit delimiter
39-
const AUD = 9;
40-
41-
/// End of sequence
42-
const END_SEQ = 10;
43-
44-
/// End of stream
45-
const END_STREAM = 11;
46-
47-
/// Filler data
48-
const FILLER_DATA = 12;
49-
50-
/// Sequence parameter set extension
51-
const SPS_EXT = 13;
52-
53-
/// Prefix NAL unit
54-
const PREFIX_NALU = 14;
55-
56-
/// Subset sequence parameter set
57-
const SUBSET_SPS = 15;
58-
59-
/// Depth parameter set
60-
const DPS = 16;
61-
62-
// 17, 18 reserved
63-
64-
/// Coded slice of an auxiliary coded picture without partitioning
65-
const SLICE_AUX = 19;
66-
67-
/// Coded slice extension
68-
const SLICE_EXT = 20;
69-
70-
/// Coded slice extension for a depth view component or a 3D-AVC texture view component
71-
const SLICE_LAYER_EXT = 21;
72-
73-
// 22, 23 reserved
74-
75-
List<int> findNALUIndices(Uint8List stream) {
76-
final result = <int>[];
77-
var start = 0, pos = 0, searchLength = stream.length - 2;
78-
while (pos < searchLength) {
79-
// skip until end of current NALU
80-
while (pos < searchLength && !(stream[pos] == 0 && stream[pos + 1] == 0 && stream[pos + 2] == 1)) {
81-
pos++;
82-
}
83-
if (pos >= searchLength) pos = stream.length;
84-
// remove trailing zeros from current NALU
85-
var end = pos;
86-
while (end > start && stream[end - 1] == 0) {
87-
end--;
88-
}
89-
// save current NALU
90-
if (start == 0) {
91-
if (end != start) throw Exception('byte stream contains leading data');
92-
} else {
93-
result.add(start);
94-
}
95-
// begin new NALU
96-
start = pos = pos + 3;
97-
}
98-
return result;
99-
}
100-
101-
int parseNALUType(int startByte) {
102-
return startByte & kNaluTypeMask;
103-
}
13+
const IV_LENGTH = 12;
10414

10515
enum CryptorError {
10616
kNew,
@@ -276,23 +186,26 @@ class FrameCryptor {
276186
}
277187
}
278188

279-
if (codec != null && codec.toLowerCase() == 'h264') {
280-
final naluIndices = findNALUIndices(data);
281-
for (var index in naluIndices) {
282-
final type = parseNALUType(data[index]);
283-
switch (type) {
284-
case SLICE_IDR:
285-
case SLICE_NON_IDR:
286-
// skipping
287-
logger.finer('unEncryptedBytes NALU of type $type, offset ${index + 2}');
288-
return index + 2;
289-
default:
290-
logger.finer('skipping NALU of type $type');
291-
break;
189+
if (['h264', 'h265'].contains(codec?.toLowerCase() ?? '')) {
190+
final result = processNALUsForEncryption(data, codec!);
191+
if (result.detectedCodec == 'unknown') {
192+
if (lastError != CryptorError.kUnsupportedCodec) {
193+
lastError = CryptorError.kUnsupportedCodec;
194+
postMessage({
195+
'type': 'cryptorState',
196+
'msgType': 'event',
197+
'participantId': participantIdentity,
198+
'trackId': trackId,
199+
'kind': kind,
200+
'state': 'unsupportedCodec',
201+
'error': 'Unsupported codec for track $trackId, detected codec ${result.detectedCodec}'
202+
});
292203
}
204+
throw Exception('Unsupported codec for track $trackId');
293205
}
294-
throw Exception('Could not find NALU');
206+
return result.unencryptedBytes;
295207
}
208+
296209
switch (frameType) {
297210
case 'key':
298211
return 10;

0 commit comments

Comments
 (0)