@livekit/react-native 2.5.1 → 2.6.0
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 +4 -3
- package/android/build.gradle +2 -1
- package/android/src/main/java/com/livekit/reactnative/LiveKitReactNative.kt +61 -5
- package/android/src/main/java/com/livekit/reactnative/LivekitReactNativeModule.kt +81 -4
- package/android/src/main/java/com/livekit/reactnative/audio/events/Events.kt +6 -0
- package/android/src/main/java/com/livekit/reactnative/audio/processing/AudioFormat.kt +2 -0
- package/android/src/main/java/com/livekit/reactnative/audio/processing/AudioProcessingController.kt +27 -0
- package/android/src/main/java/com/livekit/reactnative/audio/processing/AudioProcessorInterface.kt +52 -0
- package/android/src/main/java/com/livekit/reactnative/audio/processing/AudioRecordSamplesDispatcher.kt +72 -0
- package/android/src/main/java/com/livekit/reactnative/audio/processing/AudioSinkManager.kt +75 -0
- package/android/src/main/java/com/livekit/reactnative/audio/processing/CustomAudioProcessingFactory.kt +78 -0
- package/android/src/main/java/com/livekit/reactnative/audio/processing/MultibandVolumeProcessor.kt +181 -0
- package/android/src/main/java/com/livekit/reactnative/audio/processing/VolumeProcessor.kt +67 -0
- package/android/src/main/java/com/livekit/reactnative/audio/processing/fft/FFTAudioAnalyzer.kt +224 -0
- package/ios/LKAudioProcessingAdapter.h +26 -0
- package/ios/LKAudioProcessingAdapter.m +117 -0
- package/ios/LKAudioProcessingManager.h +34 -0
- package/ios/LKAudioProcessingManager.m +63 -0
- package/ios/LivekitReactNative-Bridging-Header.h +2 -0
- package/ios/LivekitReactNative.h +9 -4
- package/ios/LivekitReactNative.m +83 -5
- package/ios/Logging.swift +4 -0
- package/ios/audio/AVAudioPCMBuffer.swift +136 -0
- package/ios/audio/AudioProcessing.swift +163 -0
- package/ios/audio/AudioRendererManager.swift +72 -0
- package/ios/audio/FFTProcessor.swift +147 -0
- package/ios/audio/MultibandVolumeAudioRenderer.swift +65 -0
- package/ios/audio/RingBuffer.swift +51 -0
- package/ios/audio/VolumeAudioRenderer.swift +48 -0
- package/lib/commonjs/LKNativeModule.js +18 -0
- package/lib/commonjs/LKNativeModule.js.map +1 -0
- package/lib/commonjs/components/BarVisualizer.js +192 -0
- package/lib/commonjs/components/BarVisualizer.js.map +1 -0
- package/lib/commonjs/events/EventEmitter.js +45 -0
- package/lib/commonjs/events/EventEmitter.js.map +1 -0
- package/lib/commonjs/hooks/useMultibandTrackVolume.js +64 -0
- package/lib/commonjs/hooks/useMultibandTrackVolume.js.map +1 -0
- package/lib/commonjs/hooks/useTrackVolume.js +45 -0
- package/lib/commonjs/hooks/useTrackVolume.js.map +1 -0
- package/lib/commonjs/hooks.js +24 -0
- package/lib/commonjs/hooks.js.map +1 -1
- package/lib/commonjs/index.js +14 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/LKNativeModule.js +12 -0
- package/lib/module/LKNativeModule.js.map +1 -0
- package/lib/module/components/BarVisualizer.js +182 -0
- package/lib/module/components/BarVisualizer.js.map +1 -0
- package/lib/module/events/EventEmitter.js +36 -0
- package/lib/module/events/EventEmitter.js.map +1 -0
- package/lib/module/hooks/useMultibandTrackVolume.js +58 -0
- package/lib/module/hooks/useMultibandTrackVolume.js.map +1 -0
- package/lib/module/hooks/useTrackVolume.js +39 -0
- package/lib/module/hooks/useTrackVolume.js.map +1 -0
- package/lib/module/hooks.js +2 -0
- package/lib/module/hooks.js.map +1 -1
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/lib/commonjs/LKNativeModule.d.ts +3 -0
- package/lib/typescript/lib/commonjs/components/BarVisualizer.d.ts +32 -0
- package/lib/typescript/lib/commonjs/events/EventEmitter.d.ts +4 -0
- package/lib/typescript/lib/commonjs/hooks/useMultibandTrackVolume.d.ts +8 -0
- package/lib/typescript/lib/commonjs/hooks/useTrackVolume.d.ts +8 -0
- package/lib/typescript/lib/module/LKNativeModule.d.ts +2 -0
- package/lib/typescript/lib/module/components/BarVisualizer.d.ts +10 -0
- package/lib/typescript/lib/module/events/EventEmitter.d.ts +3 -0
- package/lib/typescript/lib/module/hooks/useMultibandTrackVolume.d.ts +7 -0
- package/lib/typescript/lib/module/hooks/useTrackVolume.d.ts +7 -0
- package/lib/typescript/lib/module/hooks.d.ts +2 -0
- package/lib/typescript/lib/module/index.d.ts +1 -0
- package/lib/typescript/src/LKNativeModule.d.ts +2 -0
- package/lib/typescript/src/components/BarVisualizer.d.ts +49 -0
- package/lib/typescript/src/events/EventEmitter.d.ts +6 -0
- package/lib/typescript/src/hooks/useMultibandTrackVolume.d.ts +31 -0
- package/lib/typescript/src/hooks/useTrackVolume.d.ts +9 -0
- package/lib/typescript/src/hooks.d.ts +2 -0
- package/lib/typescript/src/index.d.ts +1 -0
- package/livekit-react-native.podspec +1 -1
- package/package.json +5 -5
- package/src/LKNativeModule.ts +19 -0
- package/src/components/BarVisualizer.tsx +252 -0
- package/src/events/EventEmitter.ts +51 -0
- package/src/hooks/useMultibandTrackVolume.ts +97 -0
- package/src/hooks/useTrackVolume.ts +62 -0
- package/src/hooks.ts +2 -0
- package/src/index.tsx +3 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 LiveKit
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import Accelerate
|
|
18
|
+
import AVFoundation
|
|
19
|
+
|
|
20
|
+
extension Float {
|
|
21
|
+
var nyquistFrequency: Float { self / 2.0 }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public struct FFTComputeBandsResult {
|
|
25
|
+
let count: Int
|
|
26
|
+
let magnitudes: [Float]
|
|
27
|
+
let frequencies: [Float]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public class FFTResult {
|
|
31
|
+
public let magnitudes: [Float]
|
|
32
|
+
|
|
33
|
+
init(magnitudes: [Float]) {
|
|
34
|
+
self.magnitudes = magnitudes
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
func computeBands(minFrequency: Float, maxFrequency: Float, bandsCount: Int, sampleRate: Float) -> FFTComputeBandsResult {
|
|
38
|
+
let actualMaxFrequency = min(sampleRate.nyquistFrequency, maxFrequency)
|
|
39
|
+
var bandMagnitudes = [Float](repeating: 0.0, count: bandsCount)
|
|
40
|
+
var bandFrequencies = [Float](repeating: 0.0, count: bandsCount)
|
|
41
|
+
|
|
42
|
+
let magLowerRange = _magnitudeIndex(for: minFrequency, sampleRate: sampleRate)
|
|
43
|
+
let magUpperRange = _magnitudeIndex(for: actualMaxFrequency, sampleRate: sampleRate)
|
|
44
|
+
let ratio = Float(magUpperRange - magLowerRange) / Float(bandsCount)
|
|
45
|
+
|
|
46
|
+
return magnitudes.withUnsafeBufferPointer { magnitudesPtr in
|
|
47
|
+
for i in 0 ..< bandsCount {
|
|
48
|
+
let magsStartIdx = vDSP_Length(floorf(Float(i) * ratio)) + magLowerRange
|
|
49
|
+
let magsEndIdx = vDSP_Length(floorf(Float(i + 1) * ratio)) + magLowerRange
|
|
50
|
+
|
|
51
|
+
let count = magsEndIdx - magsStartIdx
|
|
52
|
+
if count > 0 {
|
|
53
|
+
var sum: Float = 0
|
|
54
|
+
vDSP_sve(magnitudesPtr.baseAddress! + Int(magsStartIdx), 1, &sum, count)
|
|
55
|
+
bandMagnitudes[i] = sum / Float(count)
|
|
56
|
+
} else {
|
|
57
|
+
bandMagnitudes[i] = magnitudes[Int(magsStartIdx)]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Compute average frequency
|
|
61
|
+
let bandwidth = sampleRate.nyquistFrequency / Float(magnitudes.count)
|
|
62
|
+
bandFrequencies[i] = (bandwidth * Float(magsStartIdx) + bandwidth * Float(magsEndIdx)) / 2
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return FFTComputeBandsResult(count: bandsCount, magnitudes: bandMagnitudes, frequencies: bandFrequencies)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@inline(__always) private func _magnitudeIndex(for frequency: Float, sampleRate: Float) -> vDSP_Length {
|
|
70
|
+
vDSP_Length(Float(magnitudes.count) * frequency / sampleRate.nyquistFrequency)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
class FFTProcessor {
|
|
75
|
+
public enum WindowType {
|
|
76
|
+
case none
|
|
77
|
+
case hanning
|
|
78
|
+
case hamming
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public let bufferSize: vDSP_Length
|
|
82
|
+
public let windowType: WindowType
|
|
83
|
+
|
|
84
|
+
private let bufferHalfSize: vDSP_Length
|
|
85
|
+
private let bufferLog2Size: vDSP_Length
|
|
86
|
+
private var window: [Float] = []
|
|
87
|
+
private var fftSetup: FFTSetup
|
|
88
|
+
private var realBuffer: [Float]
|
|
89
|
+
private var imaginaryBuffer: [Float]
|
|
90
|
+
private var zeroDBReference: Float = 1.0
|
|
91
|
+
|
|
92
|
+
init(bufferSize: Int, windowType: WindowType = .hanning) {
|
|
93
|
+
self.bufferSize = vDSP_Length(bufferSize)
|
|
94
|
+
self.windowType = windowType
|
|
95
|
+
|
|
96
|
+
bufferHalfSize = vDSP_Length(bufferSize / 2)
|
|
97
|
+
bufferLog2Size = vDSP_Length(log2f(Float(bufferSize)))
|
|
98
|
+
|
|
99
|
+
realBuffer = [Float](repeating: 0.0, count: Int(bufferHalfSize))
|
|
100
|
+
imaginaryBuffer = [Float](repeating: 0.0, count: Int(bufferHalfSize))
|
|
101
|
+
window = [Float](repeating: 1.0, count: Int(bufferSize))
|
|
102
|
+
|
|
103
|
+
fftSetup = vDSP_create_fftsetup(UInt(bufferLog2Size), FFTRadix(FFT_RADIX2))!
|
|
104
|
+
|
|
105
|
+
switch windowType {
|
|
106
|
+
case .none:
|
|
107
|
+
break
|
|
108
|
+
case .hanning:
|
|
109
|
+
vDSP_hann_window(&window, vDSP_Length(bufferSize), Int32(vDSP_HANN_NORM))
|
|
110
|
+
case .hamming:
|
|
111
|
+
vDSP_hamm_window(&window, vDSP_Length(bufferSize), 0)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
deinit {
|
|
116
|
+
vDSP_destroy_fftsetup(fftSetup)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
func process(buffer: [Float]) -> FFTResult {
|
|
120
|
+
precondition(buffer.count == Int(bufferSize), "Input buffer size mismatch.")
|
|
121
|
+
|
|
122
|
+
var windowedBuffer = [Float](repeating: 0.0, count: Int(bufferSize))
|
|
123
|
+
|
|
124
|
+
vDSP_vmul(buffer, 1, window, 1, &windowedBuffer, 1, bufferSize)
|
|
125
|
+
|
|
126
|
+
return realBuffer.withUnsafeMutableBufferPointer { realPtr in
|
|
127
|
+
imaginaryBuffer.withUnsafeMutableBufferPointer { imagPtr in
|
|
128
|
+
var complexBuffer = DSPSplitComplex(realp: realPtr.baseAddress!, imagp: imagPtr.baseAddress!)
|
|
129
|
+
|
|
130
|
+
windowedBuffer.withUnsafeBufferPointer { bufferPtr in
|
|
131
|
+
let complexPtr = UnsafeRawPointer(bufferPtr.baseAddress!).bindMemory(to: DSPComplex.self, capacity: Int(bufferHalfSize))
|
|
132
|
+
vDSP_ctoz(complexPtr, 2, &complexBuffer, 1, bufferHalfSize)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
vDSP_fft_zrip(fftSetup, &complexBuffer, 1, bufferLog2Size, FFTDirection(FFT_FORWARD))
|
|
136
|
+
|
|
137
|
+
var magnitudes = [Float](repeating: 0.0, count: Int(bufferHalfSize))
|
|
138
|
+
vDSP_zvabs(&complexBuffer, 1, &magnitudes, 1, bufferHalfSize)
|
|
139
|
+
|
|
140
|
+
// Convert magnitudes to decibels
|
|
141
|
+
vDSP_vdbcon(magnitudes, 1, &zeroDBReference, &magnitudes, 1, vDSP_Length(magnitudes.count), 1)
|
|
142
|
+
|
|
143
|
+
return FFTResult(magnitudes: magnitudes)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import WebRTC
|
|
2
|
+
|
|
3
|
+
public class MultibandVolumeAudioRenderer: BaseMultibandVolumeAudioRenderer {
|
|
4
|
+
private let eventEmitter: RCTEventEmitter
|
|
5
|
+
|
|
6
|
+
@objc
|
|
7
|
+
public var reactTag: String? = nil
|
|
8
|
+
|
|
9
|
+
@objc
|
|
10
|
+
public init(
|
|
11
|
+
bands: Int,
|
|
12
|
+
minFrequency: Float,
|
|
13
|
+
maxFrequency: Float,
|
|
14
|
+
intervalMs: Float,
|
|
15
|
+
eventEmitter: RCTEventEmitter
|
|
16
|
+
) {
|
|
17
|
+
self.eventEmitter = eventEmitter
|
|
18
|
+
super.init(bands: bands,
|
|
19
|
+
minFrequency: minFrequency,
|
|
20
|
+
maxFrequency: maxFrequency,
|
|
21
|
+
intervalMs: intervalMs)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
override func onMagnitudesCalculated(_ magnitudes: [Float]) {
|
|
25
|
+
guard !magnitudes.isEmpty, let reactTag = self.reactTag
|
|
26
|
+
else { return }
|
|
27
|
+
eventEmitter.sendEvent(withName: kEventMultibandProcessed, body: [
|
|
28
|
+
"magnitudes": magnitudes,
|
|
29
|
+
"id": reactTag
|
|
30
|
+
])
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public class BaseMultibandVolumeAudioRenderer: NSObject, RTCAudioRenderer {
|
|
36
|
+
private let frameInterval: Int
|
|
37
|
+
private var skippedFrames = 0
|
|
38
|
+
private let audioProcessor: AudioVisualizeProcessor
|
|
39
|
+
|
|
40
|
+
init(
|
|
41
|
+
bands: Int,
|
|
42
|
+
minFrequency: Float,
|
|
43
|
+
maxFrequency: Float,
|
|
44
|
+
intervalMs: Float
|
|
45
|
+
) {
|
|
46
|
+
self.frameInterval = Int((intervalMs / 10.0).rounded())
|
|
47
|
+
self.audioProcessor = AudioVisualizeProcessor(minFrequency: minFrequency, maxFrequency: maxFrequency, bandsCount: bands)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public func render(pcmBuffer: AVAudioPCMBuffer) {
|
|
51
|
+
if(skippedFrames < frameInterval - 1) {
|
|
52
|
+
skippedFrames += 1
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
skippedFrames = 0
|
|
57
|
+
guard let magnitudes = audioProcessor.process(pcmBuffer: pcmBuffer)
|
|
58
|
+
else {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
onMagnitudesCalculated(magnitudes)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
func onMagnitudesCalculated(_ magnitudes: [Float]) { }
|
|
65
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 LiveKit
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import Foundation
|
|
18
|
+
|
|
19
|
+
// Simple ring-buffer used for internal audio processing. Not thread-safe.
|
|
20
|
+
class RingBuffer<T: Numeric> {
|
|
21
|
+
private var _isFull = false
|
|
22
|
+
private var _buffer: [T]
|
|
23
|
+
private var _head: Int = 0
|
|
24
|
+
|
|
25
|
+
init(size: Int) {
|
|
26
|
+
_buffer = [T](repeating: 0, count: size)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
func write(_ value: T) {
|
|
30
|
+
_buffer[_head] = value
|
|
31
|
+
_head = (_head + 1) % _buffer.count
|
|
32
|
+
if _head == 0 { _isFull = true }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
func write(_ sequence: [T]) {
|
|
36
|
+
for value in sequence {
|
|
37
|
+
write(value)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
func read() -> [T]? {
|
|
42
|
+
guard _isFull else { return nil }
|
|
43
|
+
|
|
44
|
+
if _head == 0 {
|
|
45
|
+
return _buffer // Return the entire buffer if _head is at the start
|
|
46
|
+
} else {
|
|
47
|
+
// Return the buffer in the correct order
|
|
48
|
+
return Array(_buffer[_head ..< _buffer.count] + _buffer[0 ..< _head])
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import WebRTC
|
|
2
|
+
|
|
3
|
+
public class VolumeAudioRenderer: BaseVolumeAudioRenderer {
|
|
4
|
+
private let eventEmitter: RCTEventEmitter
|
|
5
|
+
|
|
6
|
+
@objc
|
|
7
|
+
public var reactTag: String? = nil
|
|
8
|
+
|
|
9
|
+
@objc
|
|
10
|
+
public init(intervalMs: Double, eventEmitter: RCTEventEmitter) {
|
|
11
|
+
self.eventEmitter = eventEmitter
|
|
12
|
+
super.init(intervalMs: intervalMs)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
override public func onVolumeCalculated(_ audioLevels: [AudioLevel]) {
|
|
16
|
+
guard let rmsAvg = audioLevels.combine()?.average,
|
|
17
|
+
let reactTag = self.reactTag
|
|
18
|
+
else { return }
|
|
19
|
+
eventEmitter.sendEvent(withName: kEventVolumeProcessed, body: [
|
|
20
|
+
"volume": rmsAvg,
|
|
21
|
+
"id": reactTag
|
|
22
|
+
])
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public class BaseVolumeAudioRenderer: NSObject, RTCAudioRenderer {
|
|
27
|
+
private let frameInterval: Int
|
|
28
|
+
private var skippedFrames = 0
|
|
29
|
+
public init(intervalMs: Double = 30) {
|
|
30
|
+
self.frameInterval = Int((intervalMs / 10.0).rounded())
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public func render(pcmBuffer: AVAudioPCMBuffer) {
|
|
34
|
+
if(skippedFrames < frameInterval - 1) {
|
|
35
|
+
skippedFrames += 1
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
skippedFrames = 0
|
|
40
|
+
guard let pcmBuffer = pcmBuffer.convert(toCommonFormat: .pcmFormatFloat32) else { return }
|
|
41
|
+
let audioLevels = pcmBuffer.audioLevels()
|
|
42
|
+
onVolumeCalculated(audioLevels)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public func onVolumeCalculated(_ audioLevels: [AudioLevel]) {
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _reactNative = require("react-native");
|
|
8
|
+
const LINKING_ERROR = `The package '@livekit/react-native' doesn't seem to be linked. Make sure: \n\n` + _reactNative.Platform.select({
|
|
9
|
+
ios: "- You have run 'pod install'\n",
|
|
10
|
+
default: ''
|
|
11
|
+
}) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo managed workflow\n';
|
|
12
|
+
const LiveKitModule = _reactNative.NativeModules.LivekitReactNative ? _reactNative.NativeModules.LivekitReactNative : new Proxy({}, {
|
|
13
|
+
get() {
|
|
14
|
+
throw new Error(LINKING_ERROR);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
var _default = exports.default = LiveKitModule;
|
|
18
|
+
//# sourceMappingURL=LKNativeModule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_reactNative","require","LINKING_ERROR","Platform","select","ios","default","LiveKitModule","NativeModules","LivekitReactNative","Proxy","get","Error","_default","exports"],"sources":["LKNativeModule.ts"],"sourcesContent":["import { NativeModules, Platform } from 'react-native';\nconst LINKING_ERROR =\n `The package '@livekit/react-native' doesn't seem to be linked. Make sure: \\n\\n` +\n Platform.select({ ios: \"- You have run 'pod install'\\n\", default: '' }) +\n '- You rebuilt the app after installing the package\\n' +\n '- You are not using Expo managed workflow\\n';\n\nconst LiveKitModule = NativeModules.LivekitReactNative\n ? NativeModules.LivekitReactNative\n : new Proxy(\n {},\n {\n get() {\n throw new Error(LINKING_ERROR);\n },\n }\n );\n\nexport default LiveKitModule;\n"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AACA,MAAMC,aAAa,GACjB,gFAAgF,GAChFC,qBAAQ,CAACC,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,6CAA6C;AAE/C,MAAMC,aAAa,GAAGC,0BAAa,CAACC,kBAAkB,GAClDD,0BAAa,CAACC,kBAAkB,GAChC,IAAIC,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIC,KAAK,CAACV,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAAC,IAAAW,QAAA,GAAAC,OAAA,CAAAR,OAAA,GAESC,aAAa","ignoreList":[]}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useBarAnimator = exports.BarVisualizer = void 0;
|
|
7
|
+
var _componentsReact = require("@livekit/components-react");
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _hooks = require("../hooks");
|
|
10
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
11
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
12
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
13
|
+
const defaultBarOptions = {
|
|
14
|
+
maxHeight: 1,
|
|
15
|
+
minHeight: 0.2,
|
|
16
|
+
barColor: '#888888',
|
|
17
|
+
barWidth: 24,
|
|
18
|
+
barBorderRadius: 12
|
|
19
|
+
};
|
|
20
|
+
const sequencerIntervals = new Map([['connecting', 2000], ['initializing', 2000], ['listening', 500], ['thinking', 150]]);
|
|
21
|
+
const getSequencerInterval = (state, barCount) => {
|
|
22
|
+
if (state === undefined) {
|
|
23
|
+
return 1000;
|
|
24
|
+
}
|
|
25
|
+
let interval = sequencerIntervals.get(state);
|
|
26
|
+
if (interval) {
|
|
27
|
+
switch (state) {
|
|
28
|
+
case 'connecting':
|
|
29
|
+
// case 'thinking':
|
|
30
|
+
interval /= barCount;
|
|
31
|
+
break;
|
|
32
|
+
default:
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return interval;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* @beta
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Visualizes audio signals from a TrackReference as bars.
|
|
44
|
+
* If the `state` prop is set, it automatically transitions between VoiceAssistant states.
|
|
45
|
+
* @beta
|
|
46
|
+
*
|
|
47
|
+
* @remarks For VoiceAssistant state transitions this component requires a voice assistant agent running with livekit-agents \>= 0.9.0
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```tsx
|
|
51
|
+
* function SimpleVoiceAssistant() {
|
|
52
|
+
* const { state, audioTrack } = useVoiceAssistant();
|
|
53
|
+
* return (
|
|
54
|
+
* <BarVisualizer
|
|
55
|
+
* state={state}
|
|
56
|
+
* trackRef={audioTrack}
|
|
57
|
+
* />
|
|
58
|
+
* );
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
const BarVisualizer = ({
|
|
63
|
+
style = {},
|
|
64
|
+
state,
|
|
65
|
+
barCount = 5,
|
|
66
|
+
trackRef,
|
|
67
|
+
options
|
|
68
|
+
}) => {
|
|
69
|
+
let trackReference = (0, _componentsReact.useMaybeTrackRefContext)();
|
|
70
|
+
if (trackRef) {
|
|
71
|
+
trackReference = trackRef;
|
|
72
|
+
}
|
|
73
|
+
const opacityAnimations = (0, _react.useRef)([]).current;
|
|
74
|
+
let magnitudes = (0, _hooks.useMultibandTrackVolume)(trackReference, {
|
|
75
|
+
bands: barCount
|
|
76
|
+
});
|
|
77
|
+
let opts = {
|
|
78
|
+
...defaultBarOptions,
|
|
79
|
+
...options
|
|
80
|
+
};
|
|
81
|
+
const highlightedIndices = useBarAnimator(state, barCount, getSequencerInterval(state, barCount) ?? 100);
|
|
82
|
+
(0, _react.useEffect)(() => {
|
|
83
|
+
let animations = [];
|
|
84
|
+
for (let i = 0; i < barCount; i++) {
|
|
85
|
+
if (!opacityAnimations[i]) {
|
|
86
|
+
opacityAnimations[i] = new _reactNative.Animated.Value(0.3);
|
|
87
|
+
}
|
|
88
|
+
let targetOpacity = 0.3;
|
|
89
|
+
if (highlightedIndices.includes(i)) {
|
|
90
|
+
targetOpacity = 1;
|
|
91
|
+
}
|
|
92
|
+
animations.push(_reactNative.Animated.timing(opacityAnimations[i], {
|
|
93
|
+
toValue: targetOpacity,
|
|
94
|
+
duration: 250,
|
|
95
|
+
useNativeDriver: true
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
let parallel = _reactNative.Animated.parallel(animations);
|
|
99
|
+
parallel.start();
|
|
100
|
+
return () => {
|
|
101
|
+
parallel.stop();
|
|
102
|
+
};
|
|
103
|
+
}, [highlightedIndices, barCount, opacityAnimations]);
|
|
104
|
+
let bars = [];
|
|
105
|
+
magnitudes.forEach((value, index) => {
|
|
106
|
+
let coerced = Math.min(opts.maxHeight, Math.max(opts.minHeight, value));
|
|
107
|
+
let coercedPercent = Math.min(100, Math.max(0, coerced * 100 + 5));
|
|
108
|
+
let opacity = opacityAnimations[index] ?? new _reactNative.Animated.Value(0.3);
|
|
109
|
+
let barStyle = {
|
|
110
|
+
opacity: opacity,
|
|
111
|
+
backgroundColor: opts.barColor,
|
|
112
|
+
borderRadius: opts.barBorderRadius,
|
|
113
|
+
width: opts.barWidth
|
|
114
|
+
};
|
|
115
|
+
bars.push( /*#__PURE__*/_react.default.createElement(_reactNative.Animated.View, {
|
|
116
|
+
key: index,
|
|
117
|
+
style: [{
|
|
118
|
+
height: `${coercedPercent}%`
|
|
119
|
+
}, barStyle, styles.volumeIndicator]
|
|
120
|
+
}));
|
|
121
|
+
});
|
|
122
|
+
return /*#__PURE__*/_react.default.createElement(_reactNative.View, {
|
|
123
|
+
style: {
|
|
124
|
+
...style,
|
|
125
|
+
...styles.container
|
|
126
|
+
}
|
|
127
|
+
}, bars);
|
|
128
|
+
};
|
|
129
|
+
exports.BarVisualizer = BarVisualizer;
|
|
130
|
+
const styles = _reactNative.StyleSheet.create({
|
|
131
|
+
container: {
|
|
132
|
+
flexDirection: 'row',
|
|
133
|
+
alignItems: 'center',
|
|
134
|
+
justifyContent: 'space-evenly'
|
|
135
|
+
},
|
|
136
|
+
volumeIndicator: {
|
|
137
|
+
borderRadius: 12
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
const useBarAnimator = (state, columns, interval) => {
|
|
141
|
+
const [index, setIndex] = (0, _react.useState)(0);
|
|
142
|
+
const [sequence, setSequence] = (0, _react.useState)([[]]);
|
|
143
|
+
(0, _react.useEffect)(() => {
|
|
144
|
+
if (state === 'thinking') {
|
|
145
|
+
setSequence(generateListeningSequenceBar(columns));
|
|
146
|
+
} else if (state === 'connecting' || state === 'initializing') {
|
|
147
|
+
const seq = [...generateConnectingSequenceBar(columns)];
|
|
148
|
+
setSequence(seq);
|
|
149
|
+
} else if (state === 'listening') {
|
|
150
|
+
setSequence(generateListeningSequenceBar(columns));
|
|
151
|
+
} else if (state === undefined) {
|
|
152
|
+
// highlight everything
|
|
153
|
+
setSequence([new Array(columns).fill(0).map((_, idx) => idx)]);
|
|
154
|
+
} else {
|
|
155
|
+
setSequence([[]]);
|
|
156
|
+
}
|
|
157
|
+
setIndex(0);
|
|
158
|
+
}, [state, columns]);
|
|
159
|
+
const animationFrameId = (0, _react.useRef)(null);
|
|
160
|
+
(0, _react.useEffect)(() => {
|
|
161
|
+
let startTime = performance.now();
|
|
162
|
+
const animate = time => {
|
|
163
|
+
const timeElapsed = time - startTime;
|
|
164
|
+
if (timeElapsed >= interval) {
|
|
165
|
+
setIndex(prev => prev + 1);
|
|
166
|
+
startTime = time;
|
|
167
|
+
}
|
|
168
|
+
animationFrameId.current = requestAnimationFrame(animate);
|
|
169
|
+
};
|
|
170
|
+
animationFrameId.current = requestAnimationFrame(animate);
|
|
171
|
+
return () => {
|
|
172
|
+
if (animationFrameId.current !== null) {
|
|
173
|
+
cancelAnimationFrame(animationFrameId.current);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
}, [interval, columns, state, sequence.length]);
|
|
177
|
+
return sequence[index % sequence.length];
|
|
178
|
+
};
|
|
179
|
+
exports.useBarAnimator = useBarAnimator;
|
|
180
|
+
const generateListeningSequenceBar = columns => {
|
|
181
|
+
const center = Math.floor(columns / 2);
|
|
182
|
+
const noIndex = -1;
|
|
183
|
+
return [[center], [noIndex]];
|
|
184
|
+
};
|
|
185
|
+
const generateConnectingSequenceBar = columns => {
|
|
186
|
+
const seq = [[]];
|
|
187
|
+
for (let x = 0; x < columns; x++) {
|
|
188
|
+
seq.push([x, columns - 1 - x]);
|
|
189
|
+
}
|
|
190
|
+
return seq;
|
|
191
|
+
};
|
|
192
|
+
//# sourceMappingURL=BarVisualizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_componentsReact","require","_reactNative","_hooks","_react","_interopRequireWildcard","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","hasOwnProperty","call","i","set","defaultBarOptions","maxHeight","minHeight","barColor","barWidth","barBorderRadius","sequencerIntervals","Map","getSequencerInterval","state","barCount","undefined","interval","BarVisualizer","style","trackRef","options","trackReference","useMaybeTrackRefContext","opacityAnimations","useRef","current","magnitudes","useMultibandTrackVolume","bands","opts","highlightedIndices","useBarAnimator","useEffect","animations","Animated","Value","targetOpacity","includes","push","timing","toValue","duration","useNativeDriver","parallel","start","stop","bars","forEach","value","index","coerced","Math","min","max","coercedPercent","opacity","barStyle","backgroundColor","borderRadius","width","createElement","View","key","height","styles","volumeIndicator","container","exports","StyleSheet","create","flexDirection","alignItems","justifyContent","columns","setIndex","useState","sequence","setSequence","generateListeningSequenceBar","seq","generateConnectingSequenceBar","Array","fill","map","_","idx","animationFrameId","startTime","performance","now","animate","time","timeElapsed","prev","requestAnimationFrame","cancelAnimationFrame","length","center","floor","noIndex","x"],"sources":["BarVisualizer.tsx"],"sourcesContent":["import {\n type AgentState,\n type TrackReferenceOrPlaceholder,\n useMaybeTrackRefContext,\n} from '@livekit/components-react';\nimport {\n Animated,\n StyleSheet,\n View,\n type ColorValue,\n type DimensionValue,\n type ViewStyle,\n} from 'react-native';\nimport { useMultibandTrackVolume } from '../hooks';\nimport React, { useEffect, useRef, useState } from 'react';\nexport type BarVisualizerOptions = {\n /** decimal values from 0 to 1 */\n maxHeight?: number;\n /** decimal values from 0 to 1 */\n minHeight?: number;\n\n barColor?: ColorValue;\n barWidth?: DimensionValue;\n barBorderRadius?: number;\n};\n\nconst defaultBarOptions = {\n maxHeight: 1,\n minHeight: 0.2,\n barColor: '#888888',\n barWidth: 24,\n barBorderRadius: 12,\n} as const satisfies BarVisualizerOptions;\n\nconst sequencerIntervals = new Map<AgentState, number>([\n ['connecting', 2000],\n ['initializing', 2000],\n ['listening', 500],\n ['thinking', 150],\n]);\n\nconst getSequencerInterval = (\n state: AgentState | undefined,\n barCount: number\n): number | undefined => {\n if (state === undefined) {\n return 1000;\n }\n let interval = sequencerIntervals.get(state);\n if (interval) {\n switch (state) {\n case 'connecting':\n // case 'thinking':\n interval /= barCount;\n break;\n\n default:\n break;\n }\n }\n return interval;\n};\n/**\n * @beta\n */\nexport interface BarVisualizerProps {\n /** If set, the visualizer will transition between different voice assistant states */\n state?: AgentState;\n /** Number of bars that show up in the visualizer */\n barCount?: number;\n trackRef?: TrackReferenceOrPlaceholder;\n options?: BarVisualizerOptions;\n /**\n * Custom React Native styles for the container.\n */\n style?: ViewStyle;\n}\n\n/**\n * Visualizes audio signals from a TrackReference as bars.\n * If the `state` prop is set, it automatically transitions between VoiceAssistant states.\n * @beta\n *\n * @remarks For VoiceAssistant state transitions this component requires a voice assistant agent running with livekit-agents \\>= 0.9.0\n *\n * @example\n * ```tsx\n * function SimpleVoiceAssistant() {\n * const { state, audioTrack } = useVoiceAssistant();\n * return (\n * <BarVisualizer\n * state={state}\n * trackRef={audioTrack}\n * />\n * );\n * }\n * ```\n */\nexport const BarVisualizer = ({\n style = {},\n state,\n barCount = 5,\n trackRef,\n options,\n}: BarVisualizerProps) => {\n let trackReference = useMaybeTrackRefContext();\n\n if (trackRef) {\n trackReference = trackRef;\n }\n\n const opacityAnimations = useRef<Animated.Value[]>([]).current;\n let magnitudes = useMultibandTrackVolume(trackReference, { bands: barCount });\n\n let opts = { ...defaultBarOptions, ...options };\n\n const highlightedIndices = useBarAnimator(\n state,\n barCount,\n getSequencerInterval(state, barCount) ?? 100\n );\n\n useEffect(() => {\n let animations = [];\n for (let i = 0; i < barCount; i++) {\n if (!opacityAnimations[i]) {\n opacityAnimations[i] = new Animated.Value(0.3);\n }\n let targetOpacity = 0.3;\n if (highlightedIndices.includes(i)) {\n targetOpacity = 1;\n }\n animations.push(\n Animated.timing(opacityAnimations[i], {\n toValue: targetOpacity,\n duration: 250,\n useNativeDriver: true,\n })\n );\n }\n\n let parallel = Animated.parallel(animations);\n parallel.start();\n return () => {\n parallel.stop();\n };\n }, [highlightedIndices, barCount, opacityAnimations]);\n\n let bars: React.ReactNode[] = [];\n magnitudes.forEach((value, index) => {\n let coerced = Math.min(opts.maxHeight, Math.max(opts.minHeight, value));\n let coercedPercent = Math.min(100, Math.max(0, coerced * 100 + 5));\n let opacity = opacityAnimations[index] ?? new Animated.Value(0.3);\n let barStyle = {\n opacity: opacity,\n backgroundColor: opts.barColor,\n borderRadius: opts.barBorderRadius,\n width: opts.barWidth,\n };\n bars.push(\n <Animated.View\n key={index}\n style={[\n { height: `${coercedPercent}%` },\n barStyle,\n styles.volumeIndicator,\n ]}\n />\n );\n });\n\n return <View style={{ ...style, ...styles.container }}>{bars}</View>;\n};\nconst styles = StyleSheet.create({\n container: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-evenly',\n },\n volumeIndicator: {\n borderRadius: 12,\n },\n});\n\nexport const useBarAnimator = (\n state: AgentState | undefined,\n columns: number,\n interval: number\n): number[] => {\n const [index, setIndex] = useState(0);\n const [sequence, setSequence] = useState<number[][]>([[]]);\n\n useEffect(() => {\n if (state === 'thinking') {\n setSequence(generateListeningSequenceBar(columns));\n } else if (state === 'connecting' || state === 'initializing') {\n const seq = [...generateConnectingSequenceBar(columns)];\n setSequence(seq);\n } else if (state === 'listening') {\n setSequence(generateListeningSequenceBar(columns));\n } else if (state === undefined) {\n // highlight everything\n setSequence([new Array(columns).fill(0).map((_, idx) => idx)]);\n } else {\n setSequence([[]]);\n }\n setIndex(0);\n }, [state, columns]);\n\n const animationFrameId = useRef<number | null>(null);\n useEffect(() => {\n let startTime = performance.now();\n\n const animate = (time: number) => {\n const timeElapsed = time - startTime;\n\n if (timeElapsed >= interval) {\n setIndex((prev) => prev + 1);\n startTime = time;\n }\n\n animationFrameId.current = requestAnimationFrame(animate);\n };\n\n animationFrameId.current = requestAnimationFrame(animate);\n\n return () => {\n if (animationFrameId.current !== null) {\n cancelAnimationFrame(animationFrameId.current);\n }\n };\n }, [interval, columns, state, sequence.length]);\n\n return sequence[index % sequence.length];\n};\n\nconst generateListeningSequenceBar = (columns: number): number[][] => {\n const center = Math.floor(columns / 2);\n const noIndex = -1;\n\n return [[center], [noIndex]];\n};\n\nconst generateConnectingSequenceBar = (columns: number): number[][] => {\n const seq: number[][] = [[]];\n\n for (let x = 0; x < columns; x++) {\n seq.push([x, columns - 1 - x]);\n }\n\n return seq;\n};\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.addListener = addListener;
|
|
7
|
+
exports.removeListener = removeListener;
|
|
8
|
+
exports.setupNativeEvents = setupNativeEvents;
|
|
9
|
+
var _reactNative = require("react-native");
|
|
10
|
+
var _EventEmitter = _interopRequireDefault(require("react-native/Libraries/vendor/emitter/EventEmitter"));
|
|
11
|
+
var _LKNativeModule = _interopRequireDefault(require("../LKNativeModule"));
|
|
12
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
|
|
15
|
+
// This emitter is going to be used to listen to all the native events (once) and then
|
|
16
|
+
// re-emit them on a JS-only emitter.
|
|
17
|
+
const nativeEmitter = new _reactNative.NativeEventEmitter(_LKNativeModule.default);
|
|
18
|
+
const NATIVE_EVENTS = ['LK_VOLUME_PROCESSED', 'LK_MULTIBAND_PROCESSED'];
|
|
19
|
+
const eventEmitter = new _EventEmitter.default();
|
|
20
|
+
function setupNativeEvents() {
|
|
21
|
+
for (const eventName of NATIVE_EVENTS) {
|
|
22
|
+
nativeEmitter.addListener(eventName, (...args) => {
|
|
23
|
+
eventEmitter.emit(eventName, ...args);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const _subscriptions = new Map();
|
|
28
|
+
function addListener(listener, eventName, eventHandler) {
|
|
29
|
+
var _subscriptions$get;
|
|
30
|
+
if (!NATIVE_EVENTS.includes(eventName)) {
|
|
31
|
+
throw new Error(`Invalid event: ${eventName}`);
|
|
32
|
+
}
|
|
33
|
+
if (!_subscriptions.has(listener)) {
|
|
34
|
+
_subscriptions.set(listener, []);
|
|
35
|
+
}
|
|
36
|
+
(_subscriptions$get = _subscriptions.get(listener)) === null || _subscriptions$get === void 0 || _subscriptions$get.push(eventEmitter.addListener(eventName, eventHandler));
|
|
37
|
+
}
|
|
38
|
+
function removeListener(listener) {
|
|
39
|
+
var _subscriptions$get2;
|
|
40
|
+
(_subscriptions$get2 = _subscriptions.get(listener)) === null || _subscriptions$get2 === void 0 || _subscriptions$get2.forEach(sub => {
|
|
41
|
+
sub.remove();
|
|
42
|
+
});
|
|
43
|
+
_subscriptions.delete(listener);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=EventEmitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_reactNative","require","_EventEmitter","_interopRequireDefault","_LKNativeModule","e","__esModule","default","nativeEmitter","NativeEventEmitter","LiveKitModule","NATIVE_EVENTS","eventEmitter","EventEmitter","setupNativeEvents","eventName","addListener","args","emit","_subscriptions","Map","listener","eventHandler","_subscriptions$get","includes","Error","has","set","get","push","removeListener","_subscriptions$get2","forEach","sub","remove","delete"],"sources":["EventEmitter.ts"],"sourcesContent":["import { NativeEventEmitter, type EmitterSubscription } from 'react-native';\n// @ts-ignore\nimport EventEmitter from 'react-native/Libraries/vendor/emitter/EventEmitter';\nimport LiveKitModule from '../LKNativeModule';\n\n// This emitter is going to be used to listen to all the native events (once) and then\n// re-emit them on a JS-only emitter.\nconst nativeEmitter = new NativeEventEmitter(LiveKitModule);\n\nconst NATIVE_EVENTS = ['LK_VOLUME_PROCESSED', 'LK_MULTIBAND_PROCESSED'];\n\nconst eventEmitter = new EventEmitter();\n\nexport function setupNativeEvents() {\n for (const eventName of NATIVE_EVENTS) {\n nativeEmitter.addListener(eventName, (...args) => {\n eventEmitter.emit(eventName, ...args);\n });\n }\n}\n\ntype EventHandler = (event: unknown) => void;\ntype Listener = unknown;\n\nconst _subscriptions: Map<Listener, EmitterSubscription[]> = new Map();\n\nexport function addListener(\n listener: Listener,\n eventName: string,\n eventHandler: EventHandler\n): void {\n if (!NATIVE_EVENTS.includes(eventName)) {\n throw new Error(`Invalid event: ${eventName}`);\n }\n\n if (!_subscriptions.has(listener)) {\n _subscriptions.set(listener, []);\n }\n\n _subscriptions\n .get(listener)\n ?.push(eventEmitter.addListener(eventName, eventHandler));\n}\n\nexport function removeListener(listener: Listener): void {\n _subscriptions.get(listener)?.forEach((sub) => {\n sub.remove();\n });\n\n _subscriptions.delete(listener);\n}\n"],"mappings":";;;;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAEA,IAAAC,aAAA,GAAAC,sBAAA,CAAAF,OAAA;AACA,IAAAG,eAAA,GAAAD,sBAAA,CAAAF,OAAA;AAA8C,SAAAE,uBAAAE,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAF9C;;AAIA;AACA;AACA,MAAMG,aAAa,GAAG,IAAIC,+BAAkB,CAACC,uBAAa,CAAC;AAE3D,MAAMC,aAAa,GAAG,CAAC,qBAAqB,EAAE,wBAAwB,CAAC;AAEvE,MAAMC,YAAY,GAAG,IAAIC,qBAAY,CAAC,CAAC;AAEhC,SAASC,iBAAiBA,CAAA,EAAG;EAClC,KAAK,MAAMC,SAAS,IAAIJ,aAAa,EAAE;IACrCH,aAAa,CAACQ,WAAW,CAACD,SAAS,EAAE,CAAC,GAAGE,IAAI,KAAK;MAChDL,YAAY,CAACM,IAAI,CAACH,SAAS,EAAE,GAAGE,IAAI,CAAC;IACvC,CAAC,CAAC;EACJ;AACF;AAKA,MAAME,cAAoD,GAAG,IAAIC,GAAG,CAAC,CAAC;AAE/D,SAASJ,WAAWA,CACzBK,QAAkB,EAClBN,SAAiB,EACjBO,YAA0B,EACpB;EAAA,IAAAC,kBAAA;EACN,IAAI,CAACZ,aAAa,CAACa,QAAQ,CAACT,SAAS,CAAC,EAAE;IACtC,MAAM,IAAIU,KAAK,CAAC,kBAAkBV,SAAS,EAAE,CAAC;EAChD;EAEA,IAAI,CAACI,cAAc,CAACO,GAAG,CAACL,QAAQ,CAAC,EAAE;IACjCF,cAAc,CAACQ,GAAG,CAACN,QAAQ,EAAE,EAAE,CAAC;EAClC;EAEA,CAAAE,kBAAA,GAAAJ,cAAc,CACXS,GAAG,CAACP,QAAQ,CAAC,cAAAE,kBAAA,eADhBA,kBAAA,CAEIM,IAAI,CAACjB,YAAY,CAACI,WAAW,CAACD,SAAS,EAAEO,YAAY,CAAC,CAAC;AAC7D;AAEO,SAASQ,cAAcA,CAACT,QAAkB,EAAQ;EAAA,IAAAU,mBAAA;EACvD,CAAAA,mBAAA,GAAAZ,cAAc,CAACS,GAAG,CAACP,QAAQ,CAAC,cAAAU,mBAAA,eAA5BA,mBAAA,CAA8BC,OAAO,CAAEC,GAAG,IAAK;IAC7CA,GAAG,CAACC,MAAM,CAAC,CAAC;EACd,CAAC,CAAC;EAEFf,cAAc,CAACgB,MAAM,CAACd,QAAQ,CAAC;AACjC","ignoreList":[]}
|