@livekit/react-native 2.9.1 → 2.9.3
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/android/build.gradle +1 -1
- package/android/consumer-rules.pro +1 -0
- package/android/src/main/AndroidManifest.xml +0 -1
- package/ios/AudioUtils.swift +38 -3
- package/ios/LiveKitReactNativeModule.swift +76 -79
- package/ios/LivekitReactNativeModule.m +7 -3
- package/lib/commonjs/audio/MediaRecorder.js +2 -2
- package/lib/commonjs/audio/MediaRecorder.js.map +1 -1
- package/lib/commonjs/e2ee/RNE2EEManager.js +73 -1
- package/lib/commonjs/e2ee/RNE2EEManager.js.map +1 -1
- package/lib/commonjs/hooks/useE2EEManager.js +1 -1
- package/lib/commonjs/hooks/useE2EEManager.js.map +1 -1
- package/lib/commonjs/index.js +10 -3
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/audio/MediaRecorder.js +1 -1
- package/lib/module/audio/MediaRecorder.js.map +1 -1
- package/lib/module/e2ee/RNE2EEManager.js +75 -3
- package/lib/module/e2ee/RNE2EEManager.js.map +1 -1
- package/lib/module/hooks/useE2EEManager.js +1 -1
- package/lib/module/hooks/useE2EEManager.js.map +1 -1
- package/lib/module/index.js +10 -4
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/lib/commonjs/e2ee/RNE2EEManager.d.ts +17 -1
- package/lib/typescript/lib/commonjs/index.d.ts +3 -1
- package/lib/typescript/lib/module/e2ee/RNE2EEManager.d.ts +17 -1
- package/lib/typescript/lib/module/index.d.ts +3 -1
- package/lib/typescript/src/e2ee/RNE2EEManager.d.ts +11 -2
- package/lib/typescript/src/hooks/useE2EEManager.d.ts +2 -2
- package/lib/typescript/src/index.d.ts +13 -2
- package/package.json +7 -6
- package/src/audio/MediaRecorder.ts +1 -1
- package/src/e2ee/RNE2EEManager.ts +117 -2
- package/src/hooks/useE2EEManager.ts +3 -2
- package/src/index.tsx +22 -3
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
import 'well-known-symbols/Symbol.asyncIterator/auto';
|
|
2
2
|
import 'well-known-symbols/Symbol.iterator/auto';
|
|
3
3
|
import './polyfills/MediaRecorderShim';
|
|
4
|
-
import 'react-native-quick-base64';
|
|
5
4
|
import './polyfills/EncoderDecoderTogether.min.js';
|
|
6
5
|
import AudioSession, { AndroidAudioTypePresets, type AndroidAudioTypeOptions, type AppleAudioCategory, type AppleAudioCategoryOption, type AppleAudioConfiguration, type AppleAudioMode, type AudioTrackState, getDefaultAppleAudioConfigurationForMode } from './audio/AudioSession';
|
|
7
6
|
import type { AudioConfiguration } from './audio/AudioSession';
|
|
8
7
|
import type { LogLevel, SetLogLevelOptions } from './logger';
|
|
9
8
|
import RNE2EEManager from './e2ee/RNE2EEManager';
|
|
10
9
|
import RNKeyProvider, { type RNKeyProviderOptions } from './e2ee/RNKeyProvider';
|
|
10
|
+
export interface RegisterGlobalsOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Automatically configure audio session before accessing microphone.
|
|
13
|
+
* When enabled, sets the iOS audio category to 'playAndRecord' before getUserMedia.
|
|
14
|
+
*
|
|
15
|
+
* @default true
|
|
16
|
+
* @platform ios
|
|
17
|
+
*/
|
|
18
|
+
autoConfigureAudioSession?: boolean;
|
|
19
|
+
}
|
|
11
20
|
/**
|
|
12
21
|
* Registers the required globals needed for LiveKit to work.
|
|
13
22
|
*
|
|
14
23
|
* Must be called before using LiveKit.
|
|
24
|
+
*
|
|
25
|
+
* @param options Optional configuration for global registration
|
|
15
26
|
*/
|
|
16
|
-
export declare function registerGlobals(): void;
|
|
27
|
+
export declare function registerGlobals(options?: RegisterGlobalsOptions): void;
|
|
17
28
|
export * from './hooks';
|
|
18
29
|
export * from './components/BarVisualizer';
|
|
19
30
|
export * from './components/LiveKitRoom';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livekit/react-native",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.3",
|
|
4
4
|
"description": "LiveKit for React Native",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -43,12 +43,13 @@
|
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@livekit/components-react": "^2.8.1",
|
|
46
|
+
"@livekit/mutex": "^1.1.1",
|
|
46
47
|
"array.prototype.at": "^1.1.1",
|
|
48
|
+
"base64-js": "1.5.1",
|
|
47
49
|
"event-target-shim": "6.0.2",
|
|
48
50
|
"events": "^3.3.0",
|
|
49
51
|
"loglevel": "^1.8.0",
|
|
50
52
|
"promise.allsettled": "^1.0.5",
|
|
51
|
-
"react-native-quick-base64": "2.1.1",
|
|
52
53
|
"react-native-url-polyfill": "^1.3.0",
|
|
53
54
|
"typed-emitter": "^2.1.0",
|
|
54
55
|
"web-streams-polyfill": "^4.1.0",
|
|
@@ -59,7 +60,7 @@
|
|
|
59
60
|
"@babel/preset-env": "^7.20.0",
|
|
60
61
|
"@babel/runtime": "^7.20.0",
|
|
61
62
|
"@commitlint/config-conventional": "^16.2.1",
|
|
62
|
-
"@livekit/react-native-webrtc": "^137.0.
|
|
63
|
+
"@livekit/react-native-webrtc": "^137.0.2",
|
|
63
64
|
"@react-native/babel-preset": "0.74.84",
|
|
64
65
|
"@react-native/eslint-config": "0.74.84",
|
|
65
66
|
"@react-native/metro-config": "0.74.84",
|
|
@@ -75,7 +76,7 @@
|
|
|
75
76
|
"eslint-plugin-prettier": "^4.2.1",
|
|
76
77
|
"husky": "^7.0.4",
|
|
77
78
|
"jest": "^29.6.3",
|
|
78
|
-
"livekit-client": "^2.15.
|
|
79
|
+
"livekit-client": "^2.15.8",
|
|
79
80
|
"pod-install": "^0.2.2",
|
|
80
81
|
"prettier": "2.8.8",
|
|
81
82
|
"react": "18.2.0",
|
|
@@ -86,8 +87,8 @@
|
|
|
86
87
|
"typescript": "5.0.4"
|
|
87
88
|
},
|
|
88
89
|
"peerDependencies": {
|
|
89
|
-
"@livekit/react-native-webrtc": "^137.0.
|
|
90
|
-
"livekit-client": "^2.15.
|
|
90
|
+
"@livekit/react-native-webrtc": "^137.0.2",
|
|
91
|
+
"livekit-client": "^2.15.8",
|
|
91
92
|
"react": "*",
|
|
92
93
|
"react-native": "*"
|
|
93
94
|
},
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
Event,
|
|
6
6
|
defineEventAttribute,
|
|
7
7
|
} from 'event-target-shim/index';
|
|
8
|
-
import { toByteArray } from '
|
|
8
|
+
import { toByteArray } from 'base64-js';
|
|
9
9
|
import LiveKitModule from '../LKNativeModule';
|
|
10
10
|
import { log } from '../logger';
|
|
11
11
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
+
RTCDataPacketCryptor,
|
|
3
|
+
RTCDataPacketCryptorFactory,
|
|
2
4
|
RTCFrameCryptorAlgorithm,
|
|
3
5
|
RTCFrameCryptorFactory,
|
|
4
6
|
RTCRtpReceiver,
|
|
7
|
+
type RTCEncryptedPacket,
|
|
5
8
|
type RTCFrameCryptor,
|
|
6
9
|
type RTCRtpSender,
|
|
7
10
|
} from '@livekit/react-native-webrtc';
|
|
@@ -16,6 +19,9 @@ import {
|
|
|
16
19
|
type BaseE2EEManager,
|
|
17
20
|
type E2EEManagerCallbacks,
|
|
18
21
|
EncryptionEvent,
|
|
22
|
+
type DecryptDataResponseMessage,
|
|
23
|
+
type EncryptDataResponseMessage,
|
|
24
|
+
Mutex,
|
|
19
25
|
} from 'livekit-client';
|
|
20
26
|
import type RNKeyProvider from './RNKeyProvider';
|
|
21
27
|
import type RTCEngine from 'livekit-client/dist/src/room/RTCEngine';
|
|
@@ -36,11 +42,28 @@ export default class RNE2EEManager
|
|
|
36
42
|
RTCFrameCryptorAlgorithm.kAesGcm;
|
|
37
43
|
|
|
38
44
|
private encryptionEnabled: boolean = false;
|
|
45
|
+
private dataChannelEncryptionEnabled: boolean = false;
|
|
39
46
|
|
|
40
|
-
|
|
47
|
+
private dataPacketCryptorLock = new Mutex();
|
|
48
|
+
private dataPacketCryptor: RTCDataPacketCryptor | undefined = undefined;
|
|
49
|
+
constructor(
|
|
50
|
+
keyProvider: RNKeyProvider,
|
|
51
|
+
dcEncryptionEnabled: boolean = false
|
|
52
|
+
) {
|
|
41
53
|
super();
|
|
42
54
|
this.keyProvider = keyProvider;
|
|
43
55
|
this.encryptionEnabled = false;
|
|
56
|
+
this.dataChannelEncryptionEnabled = dcEncryptionEnabled;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get isEnabled(): boolean {
|
|
60
|
+
return this.encryptionEnabled;
|
|
61
|
+
}
|
|
62
|
+
get isDataChannelEncryptionEnabled(): boolean {
|
|
63
|
+
return this.isEnabled && this.dataChannelEncryptionEnabled;
|
|
64
|
+
}
|
|
65
|
+
set isDataChannelEncryptionEnabled(value: boolean) {
|
|
66
|
+
this.dataChannelEncryptionEnabled = value;
|
|
44
67
|
}
|
|
45
68
|
|
|
46
69
|
setup(room: Room) {
|
|
@@ -78,7 +101,16 @@ export default class RNE2EEManager
|
|
|
78
101
|
await frameCryptor.dispose();
|
|
79
102
|
}
|
|
80
103
|
}
|
|
81
|
-
)
|
|
104
|
+
)
|
|
105
|
+
.on(RoomEvent.SignalConnected, () => {
|
|
106
|
+
if (!this.room) {
|
|
107
|
+
throw new TypeError(`expected room to be present on signal connect`);
|
|
108
|
+
}
|
|
109
|
+
this.setParticipantCryptorEnabled(
|
|
110
|
+
this.room.localParticipant.isE2EEEnabled,
|
|
111
|
+
this.room.localParticipant.identity
|
|
112
|
+
);
|
|
113
|
+
});
|
|
82
114
|
}
|
|
83
115
|
|
|
84
116
|
private async setupE2EESender(
|
|
@@ -133,6 +165,89 @@ export default class RNE2EEManager
|
|
|
133
165
|
this.keyProvider.setSifTrailer(trailer);
|
|
134
166
|
}
|
|
135
167
|
|
|
168
|
+
private async getDataPacketCryptor(): Promise<RTCDataPacketCryptor> {
|
|
169
|
+
let dataPacketCryptor = this.dataPacketCryptor;
|
|
170
|
+
if (dataPacketCryptor) {
|
|
171
|
+
return dataPacketCryptor;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
let unlock = await this.dataPacketCryptorLock.lock();
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
dataPacketCryptor = this.dataPacketCryptor;
|
|
178
|
+
if (dataPacketCryptor) {
|
|
179
|
+
return dataPacketCryptor;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
dataPacketCryptor =
|
|
183
|
+
await RTCDataPacketCryptorFactory.createDataPacketCryptor(
|
|
184
|
+
this.algorithm,
|
|
185
|
+
this.keyProvider.rtcKeyProvider
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
this.dataPacketCryptor = dataPacketCryptor;
|
|
189
|
+
return dataPacketCryptor;
|
|
190
|
+
} finally {
|
|
191
|
+
unlock();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async encryptData(
|
|
195
|
+
data: Uint8Array
|
|
196
|
+
): Promise<EncryptDataResponseMessage['data']> {
|
|
197
|
+
let room = this.room;
|
|
198
|
+
if (!room) {
|
|
199
|
+
throw new Error("e2eemanager isn't setup with room!");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
let participantId = room.localParticipant.identity;
|
|
203
|
+
|
|
204
|
+
let dataPacketCryptor = await this.getDataPacketCryptor();
|
|
205
|
+
|
|
206
|
+
let encryptedPacket = await dataPacketCryptor.encrypt(
|
|
207
|
+
participantId,
|
|
208
|
+
this.keyProvider.getLatestKeyIndex(participantId),
|
|
209
|
+
data
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
if (!encryptedPacket) {
|
|
213
|
+
throw new Error('encryption for packet failed');
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
uuid: '', //not used
|
|
217
|
+
payload: encryptedPacket.payload,
|
|
218
|
+
iv: encryptedPacket.iv,
|
|
219
|
+
keyIndex: encryptedPacket.keyIndex,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async handleEncryptedData(
|
|
224
|
+
payload: Uint8Array,
|
|
225
|
+
iv: Uint8Array,
|
|
226
|
+
participantIdentity: string,
|
|
227
|
+
keyIndex: number
|
|
228
|
+
): Promise<DecryptDataResponseMessage['data']> {
|
|
229
|
+
let packet = {
|
|
230
|
+
payload,
|
|
231
|
+
iv,
|
|
232
|
+
keyIndex,
|
|
233
|
+
} satisfies RTCEncryptedPacket;
|
|
234
|
+
|
|
235
|
+
let dataPacketCryptor = await this.getDataPacketCryptor();
|
|
236
|
+
let decryptedData = await dataPacketCryptor.decrypt(
|
|
237
|
+
participantIdentity,
|
|
238
|
+
packet
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
if (!decryptedData) {
|
|
242
|
+
throw new Error('decryption for packet failed');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return {
|
|
246
|
+
uuid: '', //not used
|
|
247
|
+
payload: decryptedData,
|
|
248
|
+
} satisfies DecryptDataResponseMessage['data'];
|
|
249
|
+
}
|
|
250
|
+
|
|
136
251
|
// Utility methods
|
|
137
252
|
//////////////////////
|
|
138
253
|
|
|
@@ -2,6 +2,7 @@ import RNE2EEManager from '../e2ee/RNE2EEManager';
|
|
|
2
2
|
import { log, RNKeyProvider } from '..';
|
|
3
3
|
import { useEffect, useState } from 'react';
|
|
4
4
|
import type { RNKeyProviderOptions } from '../e2ee/RNKeyProvider';
|
|
5
|
+
import type { BaseE2EEManager } from 'livekit-client';
|
|
5
6
|
|
|
6
7
|
export type UseRNE2EEManagerOptions = {
|
|
7
8
|
keyProviderOptions?: RNKeyProviderOptions;
|
|
@@ -10,7 +11,7 @@ export type UseRNE2EEManagerOptions = {
|
|
|
10
11
|
|
|
11
12
|
export interface RNE2EEManagerState {
|
|
12
13
|
keyProvider: RNKeyProvider;
|
|
13
|
-
e2eeManager:
|
|
14
|
+
e2eeManager: BaseE2EEManager;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -22,7 +23,7 @@ export function useRNE2EEManager(
|
|
|
22
23
|
let [keyProvider] = useState(
|
|
23
24
|
() => new RNKeyProvider(options.keyProviderOptions ?? {})
|
|
24
25
|
);
|
|
25
|
-
let [e2eeManager] = useState(() => new RNE2EEManager(keyProvider));
|
|
26
|
+
let [e2eeManager] = useState(() => new RNE2EEManager(keyProvider, false));
|
|
26
27
|
|
|
27
28
|
useEffect(() => {
|
|
28
29
|
let setup = async () => {
|
package/src/index.tsx
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import 'well-known-symbols/Symbol.asyncIterator/auto';
|
|
2
2
|
import 'well-known-symbols/Symbol.iterator/auto';
|
|
3
3
|
import './polyfills/MediaRecorderShim';
|
|
4
|
-
import 'react-native-quick-base64';
|
|
5
4
|
import { registerGlobals as webrtcRegisterGlobals } from '@livekit/react-native-webrtc';
|
|
6
5
|
import { setupURLPolyfill } from 'react-native-url-polyfill';
|
|
7
6
|
import './polyfills/EncoderDecoderTogether.min.js';
|
|
@@ -24,14 +23,34 @@ import RNKeyProvider, { type RNKeyProviderOptions } from './e2ee/RNKeyProvider';
|
|
|
24
23
|
import { setupNativeEvents } from './events/EventEmitter';
|
|
25
24
|
import { ReadableStream, WritableStream } from 'web-streams-polyfill';
|
|
26
25
|
|
|
26
|
+
export interface RegisterGlobalsOptions {
|
|
27
|
+
/**
|
|
28
|
+
* Automatically configure audio session before accessing microphone.
|
|
29
|
+
* When enabled, sets the iOS audio category to 'playAndRecord' before getUserMedia.
|
|
30
|
+
*
|
|
31
|
+
* @default true
|
|
32
|
+
* @platform ios
|
|
33
|
+
*/
|
|
34
|
+
autoConfigureAudioSession?: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
/**
|
|
28
38
|
* Registers the required globals needed for LiveKit to work.
|
|
29
39
|
*
|
|
30
40
|
* Must be called before using LiveKit.
|
|
41
|
+
*
|
|
42
|
+
* @param options Optional configuration for global registration
|
|
31
43
|
*/
|
|
32
|
-
export function registerGlobals() {
|
|
44
|
+
export function registerGlobals(options?: RegisterGlobalsOptions) {
|
|
45
|
+
const opts = {
|
|
46
|
+
autoConfigureAudioSession: true,
|
|
47
|
+
...options,
|
|
48
|
+
};
|
|
49
|
+
|
|
33
50
|
webrtcRegisterGlobals();
|
|
34
|
-
|
|
51
|
+
if (opts.autoConfigureAudioSession) {
|
|
52
|
+
iosCategoryEnforce();
|
|
53
|
+
}
|
|
35
54
|
livekitRegisterGlobals();
|
|
36
55
|
setupURLPolyfill();
|
|
37
56
|
fixWebrtcAdapter();
|