@livekit/react-native 2.5.1 → 2.6.1

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.
Files changed (95) hide show
  1. package/README.md +4 -3
  2. package/android/build.gradle +2 -1
  3. package/android/src/main/java/com/livekit/reactnative/LiveKitReactNative.kt +61 -5
  4. package/android/src/main/java/com/livekit/reactnative/LivekitReactNativeModule.kt +81 -4
  5. package/android/src/main/java/com/livekit/reactnative/audio/events/Events.kt +6 -0
  6. package/android/src/main/java/com/livekit/reactnative/audio/processing/AudioFormat.kt +2 -0
  7. package/android/src/main/java/com/livekit/reactnative/audio/processing/AudioProcessingController.kt +27 -0
  8. package/android/src/main/java/com/livekit/reactnative/audio/processing/AudioProcessorInterface.kt +52 -0
  9. package/android/src/main/java/com/livekit/reactnative/audio/processing/AudioRecordSamplesDispatcher.kt +72 -0
  10. package/android/src/main/java/com/livekit/reactnative/audio/processing/AudioSinkManager.kt +75 -0
  11. package/android/src/main/java/com/livekit/reactnative/audio/processing/CustomAudioProcessingFactory.kt +78 -0
  12. package/android/src/main/java/com/livekit/reactnative/audio/processing/MultibandVolumeProcessor.kt +181 -0
  13. package/android/src/main/java/com/livekit/reactnative/audio/processing/VolumeProcessor.kt +67 -0
  14. package/android/src/main/java/com/livekit/reactnative/audio/processing/fft/FFTAudioAnalyzer.kt +224 -0
  15. package/ios/AudioUtils.swift +49 -0
  16. package/ios/LKAudioProcessingAdapter.h +26 -0
  17. package/ios/LKAudioProcessingAdapter.m +117 -0
  18. package/ios/LKAudioProcessingManager.h +34 -0
  19. package/ios/LKAudioProcessingManager.m +63 -0
  20. package/ios/LiveKitReactNativeModule.swift +234 -0
  21. package/ios/LivekitReactNative-Bridging-Header.h +5 -2
  22. package/ios/LivekitReactNative.h +2 -6
  23. package/ios/LivekitReactNative.m +3 -166
  24. package/ios/LivekitReactNativeModule.m +42 -0
  25. package/ios/Logging.swift +4 -0
  26. package/ios/audio/AVAudioPCMBuffer.swift +136 -0
  27. package/ios/audio/AudioProcessing.swift +163 -0
  28. package/ios/audio/AudioRendererManager.swift +71 -0
  29. package/ios/audio/FFTProcessor.swift +147 -0
  30. package/ios/audio/MultibandVolumeAudioRenderer.swift +67 -0
  31. package/ios/audio/RingBuffer.swift +51 -0
  32. package/ios/audio/VolumeAudioRenderer.swift +50 -0
  33. package/lib/commonjs/LKNativeModule.js +18 -0
  34. package/lib/commonjs/LKNativeModule.js.map +1 -0
  35. package/lib/commonjs/audio/AudioSession.js +9 -17
  36. package/lib/commonjs/audio/AudioSession.js.map +1 -1
  37. package/lib/commonjs/components/BarVisualizer.js +192 -0
  38. package/lib/commonjs/components/BarVisualizer.js.map +1 -0
  39. package/lib/commonjs/events/EventEmitter.js +45 -0
  40. package/lib/commonjs/events/EventEmitter.js.map +1 -0
  41. package/lib/commonjs/hooks/useMultibandTrackVolume.js +64 -0
  42. package/lib/commonjs/hooks/useMultibandTrackVolume.js.map +1 -0
  43. package/lib/commonjs/hooks/useTrackVolume.js +45 -0
  44. package/lib/commonjs/hooks/useTrackVolume.js.map +1 -0
  45. package/lib/commonjs/hooks.js +24 -0
  46. package/lib/commonjs/hooks.js.map +1 -1
  47. package/lib/commonjs/index.js +14 -0
  48. package/lib/commonjs/index.js.map +1 -1
  49. package/lib/module/LKNativeModule.js +12 -0
  50. package/lib/module/LKNativeModule.js.map +1 -0
  51. package/lib/module/audio/AudioSession.js +9 -17
  52. package/lib/module/audio/AudioSession.js.map +1 -1
  53. package/lib/module/components/BarVisualizer.js +182 -0
  54. package/lib/module/components/BarVisualizer.js.map +1 -0
  55. package/lib/module/events/EventEmitter.js +36 -0
  56. package/lib/module/events/EventEmitter.js.map +1 -0
  57. package/lib/module/hooks/useMultibandTrackVolume.js +58 -0
  58. package/lib/module/hooks/useMultibandTrackVolume.js.map +1 -0
  59. package/lib/module/hooks/useTrackVolume.js +39 -0
  60. package/lib/module/hooks/useTrackVolume.js.map +1 -0
  61. package/lib/module/hooks.js +2 -0
  62. package/lib/module/hooks.js.map +1 -1
  63. package/lib/module/index.js +3 -0
  64. package/lib/module/index.js.map +1 -1
  65. package/lib/typescript/lib/commonjs/LKNativeModule.d.ts +3 -0
  66. package/lib/typescript/lib/commonjs/components/BarVisualizer.d.ts +32 -0
  67. package/lib/typescript/lib/commonjs/events/EventEmitter.d.ts +4 -0
  68. package/lib/typescript/lib/commonjs/hooks/useMultibandTrackVolume.d.ts +8 -0
  69. package/lib/typescript/lib/commonjs/hooks/useTrackVolume.d.ts +8 -0
  70. package/lib/typescript/lib/module/LKNativeModule.d.ts +2 -0
  71. package/lib/typescript/lib/module/components/BarVisualizer.d.ts +10 -0
  72. package/lib/typescript/lib/module/events/EventEmitter.d.ts +3 -0
  73. package/lib/typescript/lib/module/hooks/useMultibandTrackVolume.d.ts +7 -0
  74. package/lib/typescript/lib/module/hooks/useTrackVolume.d.ts +7 -0
  75. package/lib/typescript/lib/module/hooks.d.ts +2 -0
  76. package/lib/typescript/lib/module/index.d.ts +1 -0
  77. package/lib/typescript/src/LKNativeModule.d.ts +2 -0
  78. package/lib/typescript/src/components/BarVisualizer.d.ts +49 -0
  79. package/lib/typescript/src/events/EventEmitter.d.ts +6 -0
  80. package/lib/typescript/src/hooks/useMultibandTrackVolume.d.ts +31 -0
  81. package/lib/typescript/src/hooks/useTrackVolume.d.ts +9 -0
  82. package/lib/typescript/src/hooks.d.ts +2 -0
  83. package/lib/typescript/src/index.d.ts +1 -0
  84. package/livekit-react-native.podspec +26 -6
  85. package/package.json +5 -5
  86. package/src/LKNativeModule.ts +19 -0
  87. package/src/audio/AudioSession.ts +9 -24
  88. package/src/components/BarVisualizer.tsx +252 -0
  89. package/src/events/EventEmitter.ts +51 -0
  90. package/src/hooks/useMultibandTrackVolume.ts +97 -0
  91. package/src/hooks/useTrackVolume.ts +62 -0
  92. package/src/hooks.ts +2 -0
  93. package/src/index.tsx +3 -0
  94. package/ios/AudioUtils.h +0 -9
  95. package/ios/AudioUtils.m +0 -48
@@ -0,0 +1,51 @@
1
+ import { NativeEventEmitter, type EmitterSubscription } from 'react-native';
2
+ // @ts-ignore
3
+ import EventEmitter from 'react-native/Libraries/vendor/emitter/EventEmitter';
4
+ import LiveKitModule from '../LKNativeModule';
5
+
6
+ // This emitter is going to be used to listen to all the native events (once) and then
7
+ // re-emit them on a JS-only emitter.
8
+ const nativeEmitter = new NativeEventEmitter(LiveKitModule);
9
+
10
+ const NATIVE_EVENTS = ['LK_VOLUME_PROCESSED', 'LK_MULTIBAND_PROCESSED'];
11
+
12
+ const eventEmitter = new EventEmitter();
13
+
14
+ export function setupNativeEvents() {
15
+ for (const eventName of NATIVE_EVENTS) {
16
+ nativeEmitter.addListener(eventName, (...args) => {
17
+ eventEmitter.emit(eventName, ...args);
18
+ });
19
+ }
20
+ }
21
+
22
+ type EventHandler = (event: unknown) => void;
23
+ type Listener = unknown;
24
+
25
+ const _subscriptions: Map<Listener, EmitterSubscription[]> = new Map();
26
+
27
+ export function addListener(
28
+ listener: Listener,
29
+ eventName: string,
30
+ eventHandler: EventHandler
31
+ ): void {
32
+ if (!NATIVE_EVENTS.includes(eventName)) {
33
+ throw new Error(`Invalid event: ${eventName}`);
34
+ }
35
+
36
+ if (!_subscriptions.has(listener)) {
37
+ _subscriptions.set(listener, []);
38
+ }
39
+
40
+ _subscriptions
41
+ .get(listener)
42
+ ?.push(eventEmitter.addListener(eventName, eventHandler));
43
+ }
44
+
45
+ export function removeListener(listener: Listener): void {
46
+ _subscriptions.get(listener)?.forEach((sub) => {
47
+ sub.remove();
48
+ });
49
+
50
+ _subscriptions.delete(listener);
51
+ }
@@ -0,0 +1,97 @@
1
+ import { type TrackReferenceOrPlaceholder } from '@livekit/components-react';
2
+ import {
3
+ Track,
4
+ type LocalAudioTrack,
5
+ type RemoteAudioTrack,
6
+ } from 'livekit-client';
7
+ import { useEffect, useMemo, useState } from 'react';
8
+ import { addListener, removeListener } from '../events/EventEmitter';
9
+ import LiveKitModule from '../LKNativeModule';
10
+
11
+ /**
12
+ * Interface for configuring options for the useMultibandTrackVolume hook.
13
+ * @alpha
14
+ */
15
+ export interface MultiBandTrackVolumeOptions {
16
+ /**
17
+ * the number of bands to split the audio into
18
+ */
19
+ bands?: number;
20
+ /**
21
+ * cut off frequency on the lower end
22
+ */
23
+ minFrequency?: number;
24
+ /**
25
+ * cut off frequency on the higher end
26
+ */
27
+ maxFrequency?: number;
28
+ /**
29
+ * update should run every x ms
30
+ */
31
+ updateInterval?: number;
32
+ }
33
+
34
+ const multibandDefaults = {
35
+ bands: 5,
36
+ minFrequency: 1000,
37
+ maxFrequency: 8000,
38
+ updateInterval: 40,
39
+ } as const satisfies MultiBandTrackVolumeOptions;
40
+
41
+ /**
42
+ * A hook for tracking the volume of an audio track across multiple frequency bands.
43
+ *
44
+ * @param trackOrTrackReference
45
+ * @returns A number array containing the volume for each frequency band.
46
+ */
47
+ export function useMultibandTrackVolume(
48
+ trackOrTrackReference?:
49
+ | LocalAudioTrack
50
+ | RemoteAudioTrack
51
+ | TrackReferenceOrPlaceholder,
52
+ options: MultiBandTrackVolumeOptions = {}
53
+ ) {
54
+ const track =
55
+ trackOrTrackReference instanceof Track
56
+ ? trackOrTrackReference
57
+ : <LocalAudioTrack | RemoteAudioTrack | undefined>(
58
+ trackOrTrackReference?.publication?.track
59
+ );
60
+ const opts = useMemo(() => {
61
+ return { ...multibandDefaults, ...options };
62
+ }, [options]);
63
+ const mediaStreamTrack = track?.mediaStreamTrack;
64
+
65
+ let [magnitudes, setMagnitudes] = useState<number[]>([]);
66
+ useEffect(() => {
67
+ let listener = Object();
68
+ let reactTag: string | null = null;
69
+ if (mediaStreamTrack) {
70
+ reactTag = LiveKitModule.createMultibandVolumeProcessor(
71
+ opts,
72
+ mediaStreamTrack._peerConnectionId ?? -1,
73
+ mediaStreamTrack.id
74
+ );
75
+ addListener(listener, 'LK_MULTIBAND_PROCESSED', (event: any) => {
76
+ if (event.magnitudes && reactTag && event.id === reactTag) {
77
+ console.log('event received: ', event.magnitudes[0]);
78
+ setMagnitudes(event.magnitudes);
79
+ }
80
+ });
81
+ }
82
+ return () => {
83
+ if (mediaStreamTrack) {
84
+ removeListener(listener);
85
+ if (reactTag) {
86
+ LiveKitModule.deleteMultibandVolumeProcessor(
87
+ reactTag,
88
+ mediaStreamTrack._peerConnectionId ?? -1,
89
+ mediaStreamTrack.id
90
+ );
91
+ }
92
+ }
93
+ };
94
+ }, [mediaStreamTrack, opts]);
95
+
96
+ return magnitudes;
97
+ }
@@ -0,0 +1,62 @@
1
+ import { type TrackReferenceOrPlaceholder } from '@livekit/components-react';
2
+ import {
3
+ Track,
4
+ type LocalAudioTrack,
5
+ type RemoteAudioTrack,
6
+ } from 'livekit-client';
7
+ import { useEffect, useState } from 'react';
8
+ import { addListener, removeListener } from '../events/EventEmitter';
9
+ import LiveKitModule from '../LKNativeModule';
10
+
11
+ /**
12
+ * A hook for tracking the volume of an audio track.
13
+ *
14
+ * @param trackOrTrackReference
15
+ * @returns A number between 0-1 representing the volume.
16
+ */
17
+ export function useTrackVolume(
18
+ trackOrTrackReference?:
19
+ | LocalAudioTrack
20
+ | RemoteAudioTrack
21
+ | TrackReferenceOrPlaceholder
22
+ ) {
23
+ const track =
24
+ trackOrTrackReference instanceof Track
25
+ ? trackOrTrackReference
26
+ : <LocalAudioTrack | RemoteAudioTrack | undefined>(
27
+ trackOrTrackReference?.publication?.track
28
+ );
29
+
30
+ const mediaStreamTrack = track?.mediaStreamTrack;
31
+
32
+ let [volume, setVolume] = useState(0.0);
33
+ useEffect(() => {
34
+ let listener = Object();
35
+ let reactTag: string | null = null;
36
+ if (mediaStreamTrack) {
37
+ reactTag = LiveKitModule.createVolumeProcessor(
38
+ mediaStreamTrack._peerConnectionId ?? -1,
39
+ mediaStreamTrack.id
40
+ );
41
+ addListener(listener, 'LK_VOLUME_PROCESSED', (event: any) => {
42
+ if (event.volume && reactTag && event.id === reactTag) {
43
+ setVolume(event.volume);
44
+ }
45
+ });
46
+ }
47
+ return () => {
48
+ if (mediaStreamTrack) {
49
+ removeListener(listener);
50
+ if (reactTag) {
51
+ LiveKitModule.deleteVolumeProcessor(
52
+ reactTag,
53
+ mediaStreamTrack._peerConnectionId ?? -1,
54
+ mediaStreamTrack.id
55
+ );
56
+ }
57
+ }
58
+ };
59
+ }, [mediaStreamTrack]);
60
+
61
+ return volume;
62
+ }
package/src/hooks.ts CHANGED
@@ -42,4 +42,6 @@ export type {
42
42
 
43
43
  export type { ReceivedDataMessage } from '@livekit/components-core';
44
44
  export * from './hooks/useE2EEManager';
45
+ export * from './hooks/useTrackVolume';
46
+ export * from './hooks/useMultibandTrackVolume';
45
47
  export type { UseRNE2EEManagerOptions } from './hooks/useE2EEManager';
package/src/index.tsx CHANGED
@@ -17,6 +17,7 @@ import { type LiveKitReactNativeInfo } from 'livekit-client';
17
17
  import type { LogLevel, SetLogLevelOptions } from './logger';
18
18
  import RNE2EEManager from './e2ee/RNE2EEManager';
19
19
  import RNKeyProvider, { type RNKeyProviderOptions } from './e2ee/RNKeyProvider';
20
+ import { setupNativeEvents } from './events/EventEmitter';
20
21
 
21
22
  /**
22
23
  * Registers the required globals needed for LiveKit to work.
@@ -33,6 +34,7 @@ export function registerGlobals() {
33
34
  shimArrayAt();
34
35
  shimAsyncIterator();
35
36
  shimIterator();
37
+ setupNativeEvents();
36
38
  }
37
39
 
38
40
  /**
@@ -99,6 +101,7 @@ function shimIterator() {
99
101
  shim();
100
102
  }
101
103
  export * from './hooks';
104
+ export * from './components/BarVisualizer';
102
105
  export * from './components/LiveKitRoom';
103
106
  export * from './components/VideoTrack';
104
107
  export * from './components/VideoView'; // deprecated
package/ios/AudioUtils.h DELETED
@@ -1,9 +0,0 @@
1
- #if TARGET_OS_IPHONE
2
- #import <AVFoundation/AVFoundation.h>
3
-
4
- @interface AudioUtils : NSObject
5
- + (AVAudioSessionMode)audioSessionModeFromString:(NSString*)mode;
6
- + (AVAudioSessionCategory)audioSessionCategoryFromString:(NSString *)category;
7
- @end
8
-
9
- #endif
package/ios/AudioUtils.m DELETED
@@ -1,48 +0,0 @@
1
- #if TARGET_OS_IPHONE
2
- #import "AudioUtils.h"
3
- #import <AVFoundation/AVFoundation.h>
4
-
5
- @implementation AudioUtils
6
-
7
- + (AVAudioSessionMode)audioSessionModeFromString:(NSString*)mode {
8
- if([@"default_" isEqualToString:mode]) {
9
- return AVAudioSessionModeDefault;
10
- } else if([@"voicePrompt" isEqualToString:mode]) {
11
- return AVAudioSessionModeVoicePrompt;
12
- } else if([@"videoRecording" isEqualToString:mode]) {
13
- return AVAudioSessionModeVideoRecording;
14
- } else if([@"videoChat" isEqualToString:mode]) {
15
- return AVAudioSessionModeVideoChat;
16
- } else if([@"voiceChat" isEqualToString:mode]) {
17
- return AVAudioSessionModeVoiceChat;
18
- } else if([@"gameChat" isEqualToString:mode]) {
19
- return AVAudioSessionModeGameChat;
20
- } else if([@"measurement" isEqualToString:mode]) {
21
- return AVAudioSessionModeMeasurement;
22
- } else if([@"moviePlayback" isEqualToString:mode]) {
23
- return AVAudioSessionModeMoviePlayback;
24
- } else if([@"spokenAudio" isEqualToString:mode]) {
25
- return AVAudioSessionModeSpokenAudio;
26
- }
27
- return AVAudioSessionModeDefault;
28
- }
29
-
30
- + (AVAudioSessionCategory)audioSessionCategoryFromString:(NSString *)category {
31
- if([@"ambient" isEqualToString:category]) {
32
- return AVAudioSessionCategoryAmbient;
33
- } else if([@"soloAmbient" isEqualToString:category]) {
34
- return AVAudioSessionCategorySoloAmbient;
35
- } else if([@"playback" isEqualToString:category]) {
36
- return AVAudioSessionCategoryPlayback;
37
- } else if([@"record" isEqualToString:category]) {
38
- return AVAudioSessionCategoryRecord;
39
- } else if([@"playAndRecord" isEqualToString:category]) {
40
- return AVAudioSessionCategoryPlayAndRecord;
41
- } else if([@"multiRoute" isEqualToString:category]) {
42
- return AVAudioSessionCategoryMultiRoute;
43
- }
44
- return AVAudioSessionCategoryAmbient;
45
- }
46
-
47
- @end
48
- #endif