react-native-audio-api 0.8.3 → 0.9.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 +40 -39
- package/RNAudioAPI.podspec +17 -12
- package/android/build.gradle +44 -4
- package/android/src/main/cpp/audioapi/CMakeLists.txt +65 -0
- package/android/src/main/cpp/audioapi/android/AudioAPIModule.cpp +29 -1
- package/android/src/main/cpp/audioapi/android/AudioAPIModule.h +14 -0
- package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +7 -1
- package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.h +6 -1
- package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +1 -1
- package/android/src/main/cpp/audioapi/android/core/NativeAudioRecorder.hpp +36 -0
- package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +11 -1
- package/android/src/main/java/com/swmansion/audioapi/core/NativeAudioRecorder.kt +24 -0
- package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +15 -2
- package/common/cpp/audioapi/AudioAPIModuleInstaller.h +53 -18
- package/common/cpp/audioapi/HostObjects/AudioContextHostObject.cpp +57 -0
- package/common/cpp/audioapi/HostObjects/AudioContextHostObject.h +6 -46
- package/common/cpp/audioapi/HostObjects/AudioNodeHostObject.cpp +70 -6
- package/common/cpp/audioapi/HostObjects/AudioNodeHostObject.h +10 -66
- package/common/cpp/audioapi/HostObjects/AudioParamHostObject.cpp +105 -0
- package/common/cpp/audioapi/HostObjects/AudioParamHostObject.h +17 -91
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +362 -6
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +29 -241
- package/common/cpp/audioapi/HostObjects/OfflineAudioContextHostObject.cpp +70 -0
- package/common/cpp/audioapi/HostObjects/OfflineAudioContextHostObject.h +6 -50
- package/common/cpp/audioapi/HostObjects/WorkletNodeHostObject.h +18 -0
- package/common/cpp/audioapi/HostObjects/WorkletProcessingNodeHostObject.h +18 -0
- package/common/cpp/audioapi/HostObjects/analysis/AnalyserNodeHostObject.cpp +148 -0
- package/common/cpp/audioapi/HostObjects/analysis/AnalyserNodeHostObject.h +37 -0
- package/common/cpp/audioapi/HostObjects/effects/BiquadFilterNodeHostObject.cpp +92 -0
- package/common/cpp/audioapi/HostObjects/effects/BiquadFilterNodeHostObject.h +29 -0
- package/common/cpp/audioapi/HostObjects/effects/GainNodeHostObject.cpp +20 -0
- package/common/cpp/audioapi/HostObjects/effects/GainNodeHostObject.h +19 -0
- package/common/cpp/audioapi/HostObjects/effects/StereoPannerNodeHostObject.cpp +21 -0
- package/common/cpp/audioapi/HostObjects/effects/StereoPannerNodeHostObject.h +21 -0
- package/common/cpp/audioapi/HostObjects/events/AudioEventHandlerRegistryHostObject.cpp +41 -0
- package/common/cpp/audioapi/HostObjects/events/AudioEventHandlerRegistryHostObject.h +28 -0
- package/common/cpp/audioapi/HostObjects/inputs/AudioRecorderHostObject.cpp +69 -0
- package/common/cpp/audioapi/HostObjects/inputs/AudioRecorderHostObject.h +33 -0
- package/common/cpp/audioapi/HostObjects/sources/AudioBufferBaseSourceNodeHostObject.cpp +73 -0
- package/common/cpp/audioapi/HostObjects/sources/AudioBufferBaseSourceNodeHostObject.h +29 -0
- package/common/cpp/audioapi/HostObjects/sources/AudioBufferHostObject.cpp +94 -0
- package/common/cpp/audioapi/HostObjects/sources/AudioBufferHostObject.h +46 -0
- package/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.cpp +60 -0
- package/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.h +25 -0
- package/common/cpp/audioapi/HostObjects/sources/AudioBufferSourceNodeHostObject.cpp +152 -0
- package/common/cpp/audioapi/HostObjects/sources/AudioBufferSourceNodeHostObject.h +37 -0
- package/common/cpp/audioapi/HostObjects/sources/AudioScheduledSourceNodeHostObject.cpp +52 -0
- package/common/cpp/audioapi/HostObjects/sources/AudioScheduledSourceNodeHostObject.h +25 -0
- package/common/cpp/audioapi/HostObjects/sources/ConstantSourceNodeHostObject.cpp +19 -0
- package/common/cpp/audioapi/HostObjects/sources/ConstantSourceNodeHostObject.h +21 -0
- package/common/cpp/audioapi/HostObjects/sources/OscillatorNodeHostObject.cpp +55 -0
- package/common/cpp/audioapi/HostObjects/sources/OscillatorNodeHostObject.h +27 -0
- package/common/cpp/audioapi/HostObjects/{RecorderAdapterNodeHostObject.h → sources/RecorderAdapterNodeHostObject.h} +1 -2
- package/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.cpp +22 -0
- package/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.h +28 -0
- package/common/cpp/audioapi/HostObjects/sources/WorkletSourceNodeHostObject.h +18 -0
- package/common/cpp/audioapi/core/AudioContext.cpp +3 -2
- package/common/cpp/audioapi/core/AudioContext.h +2 -1
- package/common/cpp/audioapi/core/AudioNode.cpp +3 -3
- package/common/cpp/audioapi/core/AudioNode.h +2 -2
- package/common/cpp/audioapi/core/AudioParam.cpp +2 -2
- package/common/cpp/audioapi/core/AudioParam.h +1 -1
- package/common/cpp/audioapi/core/BaseAudioContext.cpp +47 -3
- package/common/cpp/audioapi/core/BaseAudioContext.h +13 -4
- package/common/cpp/audioapi/core/OfflineAudioContext.cpp +4 -3
- package/common/cpp/audioapi/core/OfflineAudioContext.h +2 -1
- package/common/cpp/audioapi/core/analysis/AnalyserNode.cpp +3 -1
- package/common/cpp/audioapi/core/analysis/AnalyserNode.h +1 -1
- package/common/cpp/audioapi/core/destinations/AudioDestinationNode.h +1 -1
- package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +3 -1
- package/common/cpp/audioapi/core/effects/BiquadFilterNode.h +1 -1
- package/common/cpp/audioapi/core/effects/GainNode.cpp +3 -1
- package/common/cpp/audioapi/core/effects/GainNode.h +1 -1
- package/common/cpp/audioapi/core/effects/PeriodicWave.cpp +1 -1
- package/common/cpp/audioapi/core/effects/StereoPannerNode.cpp +18 -13
- package/common/cpp/audioapi/core/effects/StereoPannerNode.h +1 -1
- package/common/cpp/audioapi/core/effects/WorkletNode.cpp +89 -0
- package/common/cpp/audioapi/core/effects/WorkletNode.h +65 -0
- package/common/cpp/audioapi/core/effects/WorkletProcessingNode.cpp +91 -0
- package/common/cpp/audioapi/core/effects/WorkletProcessingNode.h +52 -0
- package/common/cpp/audioapi/core/inputs/AudioRecorder.cpp +1 -1
- package/common/cpp/audioapi/core/inputs/AudioRecorder.h +2 -2
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +47 -10
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +18 -3
- package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +98 -14
- package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h +9 -3
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +37 -44
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +7 -9
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +1 -6
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +1 -1
- package/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp +53 -0
- package/common/cpp/audioapi/core/sources/ConstantSourceNode.h +26 -0
- package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +7 -2
- package/common/cpp/audioapi/core/sources/OscillatorNode.h +1 -1
- package/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp +3 -1
- package/common/cpp/audioapi/core/sources/RecorderAdapterNode.h +1 -1
- package/common/cpp/audioapi/core/sources/StreamerNode.cpp +9 -1
- package/common/cpp/audioapi/core/sources/StreamerNode.h +1 -9
- package/common/cpp/audioapi/core/sources/WorkletSourceNode.cpp +84 -0
- package/common/cpp/audioapi/core/sources/WorkletSourceNode.h +47 -0
- package/common/cpp/audioapi/core/{AudioParamEventQueue.cpp → utils/AudioParamEventQueue.cpp} +13 -7
- package/common/cpp/audioapi/core/{Constants.h → utils/Constants.h} +5 -0
- package/common/cpp/audioapi/core/utils/worklets/SafeIncludes.h +52 -0
- package/common/cpp/audioapi/core/utils/worklets/WorkletsRunner.cpp +9 -0
- package/common/cpp/audioapi/core/utils/worklets/WorkletsRunner.h +73 -0
- package/common/cpp/audioapi/dsp/Windows.cpp +1 -1
- package/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp +1 -1
- package/common/cpp/audioapi/events/AudioEventHandlerRegistry.h +2 -1
- package/common/cpp/audioapi/jsi/AudioArrayBuffer.h +14 -1
- package/common/cpp/audioapi/jsi/JsiHostObject.h +6 -12
- package/common/cpp/audioapi/jsi/JsiPromise.cpp +49 -0
- package/common/cpp/audioapi/jsi/JsiPromise.h +29 -1
- package/common/cpp/audioapi/utils/AudioBus.cpp +1 -1
- package/common/cpp/audioapi/utils/ThreadPool.hpp +104 -0
- package/common/cpp/test/AudioParamTest.cpp +204 -0
- package/common/cpp/test/CMakeLists.txt +12 -3
- package/common/cpp/test/GainTest.cpp +11 -10
- package/common/cpp/test/OscillatorTest.cpp +2 -1
- package/common/cpp/test/StereoPannerTest.cpp +129 -0
- package/ios/audioapi/ios/AudioAPIModule.mm +32 -5
- package/ios/audioapi/ios/core/IOSAudioPlayer.mm +1 -1
- package/ios/audioapi/ios/core/IOSAudioRecorder.mm +1 -1
- package/lib/commonjs/api.js +36 -2
- package/lib/commonjs/api.js.map +1 -1
- package/lib/commonjs/api.web.js +8 -0
- package/lib/commonjs/api.web.js.map +1 -1
- package/lib/commonjs/core/AudioBufferBaseSourceNode.js +7 -7
- package/lib/commonjs/core/AudioBufferBaseSourceNode.js.map +1 -1
- package/lib/commonjs/core/AudioBufferQueueSourceNode.js +1 -6
- package/lib/commonjs/core/AudioBufferQueueSourceNode.js.map +1 -1
- package/lib/commonjs/core/AudioBufferSourceNode.js +15 -0
- package/lib/commonjs/core/AudioBufferSourceNode.js.map +1 -1
- package/lib/commonjs/core/AudioContext.js +10 -1
- package/lib/commonjs/core/AudioContext.js.map +1 -1
- package/lib/commonjs/core/AudioScheduledSourceNode.js +4 -4
- package/lib/commonjs/core/AudioScheduledSourceNode.js.map +1 -1
- package/lib/commonjs/core/BaseAudioContext.js +66 -11
- package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
- package/lib/commonjs/core/ConstantSourceNode.js +17 -0
- package/lib/commonjs/core/ConstantSourceNode.js.map +1 -0
- package/lib/commonjs/core/OfflineAudioContext.js +11 -2
- package/lib/commonjs/core/OfflineAudioContext.js.map +1 -1
- package/lib/commonjs/core/OscillatorNode.js +6 -0
- package/lib/commonjs/core/OscillatorNode.js.map +1 -1
- package/lib/commonjs/core/WorkletNode.js +11 -0
- package/lib/commonjs/core/WorkletNode.js.map +1 -0
- package/lib/commonjs/core/WorkletProcessingNode.js +11 -0
- package/lib/commonjs/core/WorkletProcessingNode.js.map +1 -0
- package/lib/commonjs/core/WorkletSourceNode.js +11 -0
- package/lib/commonjs/core/WorkletSourceNode.js.map +1 -0
- package/lib/commonjs/hooks/{useSytemVolume.js → useSystemVolume.js} +1 -1
- package/lib/commonjs/hooks/useSystemVolume.js.map +1 -0
- package/lib/commonjs/utils/index.js +9 -0
- package/lib/commonjs/utils/index.js.map +1 -1
- package/lib/commonjs/web-core/AudioContext.js +4 -0
- package/lib/commonjs/web-core/AudioContext.js.map +1 -1
- package/lib/commonjs/web-core/AudioScheduledSourceNode.js +1 -1
- package/lib/commonjs/web-core/AudioScheduledSourceNode.js.map +1 -1
- package/lib/commonjs/web-core/ConstantSourceNode.js +17 -0
- package/lib/commonjs/web-core/ConstantSourceNode.js.map +1 -0
- package/lib/commonjs/web-core/OfflineAudioContext.js +4 -0
- package/lib/commonjs/web-core/OfflineAudioContext.js.map +1 -1
- package/lib/module/api.js +6 -2
- package/lib/module/api.js.map +1 -1
- package/lib/module/api.web.js +1 -0
- package/lib/module/api.web.js.map +1 -1
- package/lib/module/core/AudioBufferBaseSourceNode.js +7 -7
- package/lib/module/core/AudioBufferBaseSourceNode.js.map +1 -1
- package/lib/module/core/AudioBufferQueueSourceNode.js +1 -6
- package/lib/module/core/AudioBufferQueueSourceNode.js.map +1 -1
- package/lib/module/core/AudioBufferSourceNode.js +15 -0
- package/lib/module/core/AudioBufferSourceNode.js.map +1 -1
- package/lib/module/core/AudioContext.js +10 -1
- package/lib/module/core/AudioContext.js.map +1 -1
- package/lib/module/core/AudioScheduledSourceNode.js +4 -4
- package/lib/module/core/AudioScheduledSourceNode.js.map +1 -1
- package/lib/module/core/BaseAudioContext.js +66 -11
- package/lib/module/core/BaseAudioContext.js.map +1 -1
- package/lib/module/core/ConstantSourceNode.js +11 -0
- package/lib/module/core/ConstantSourceNode.js.map +1 -0
- package/lib/module/core/OfflineAudioContext.js +11 -2
- package/lib/module/core/OfflineAudioContext.js.map +1 -1
- package/lib/module/core/OscillatorNode.js +6 -0
- package/lib/module/core/OscillatorNode.js.map +1 -1
- package/lib/module/core/WorkletNode.js +5 -0
- package/lib/module/core/WorkletNode.js.map +1 -0
- package/lib/module/core/WorkletProcessingNode.js +5 -0
- package/lib/module/core/WorkletProcessingNode.js.map +1 -0
- package/lib/module/core/WorkletSourceNode.js +5 -0
- package/lib/module/core/WorkletSourceNode.js.map +1 -0
- package/lib/module/hooks/{useSytemVolume.js → useSystemVolume.js} +1 -1
- package/lib/module/hooks/useSystemVolume.js.map +1 -0
- package/lib/module/utils/index.js +8 -0
- package/lib/module/utils/index.js.map +1 -1
- package/lib/module/web-core/AudioContext.js +4 -0
- package/lib/module/web-core/AudioContext.js.map +1 -1
- package/lib/module/web-core/AudioScheduledSourceNode.js +1 -1
- package/lib/module/web-core/AudioScheduledSourceNode.js.map +1 -1
- package/lib/module/web-core/ConstantSourceNode.js +11 -0
- package/lib/module/web-core/ConstantSourceNode.js.map +1 -0
- package/lib/module/web-core/OfflineAudioContext.js +4 -0
- package/lib/module/web-core/OfflineAudioContext.js.map +1 -1
- package/lib/typescript/api.d.ts +8 -4
- package/lib/typescript/api.d.ts.map +1 -1
- package/lib/typescript/api.web.d.ts +1 -0
- package/lib/typescript/api.web.d.ts.map +1 -1
- package/lib/typescript/core/AudioBufferBaseSourceNode.d.ts +2 -2
- package/lib/typescript/core/AudioBufferBaseSourceNode.d.ts.map +1 -1
- package/lib/typescript/core/AudioBufferQueueSourceNode.d.ts +1 -1
- package/lib/typescript/core/AudioBufferQueueSourceNode.d.ts.map +1 -1
- package/lib/typescript/core/AudioBufferSourceNode.d.ts +4 -0
- package/lib/typescript/core/AudioBufferSourceNode.d.ts.map +1 -1
- package/lib/typescript/core/AudioContext.d.ts +1 -0
- package/lib/typescript/core/AudioContext.d.ts.map +1 -1
- package/lib/typescript/core/AudioScheduledSourceNode.d.ts +1 -1
- package/lib/typescript/core/BaseAudioContext.d.ts +19 -11
- package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/core/ConstantSourceNode.d.ts +9 -0
- package/lib/typescript/core/ConstantSourceNode.d.ts.map +1 -0
- package/lib/typescript/core/OfflineAudioContext.d.ts +1 -0
- package/lib/typescript/core/OfflineAudioContext.d.ts.map +1 -1
- package/lib/typescript/core/OscillatorNode.d.ts +3 -0
- package/lib/typescript/core/OscillatorNode.d.ts.map +1 -1
- package/lib/typescript/core/WorkletNode.d.ts +4 -0
- package/lib/typescript/core/WorkletNode.d.ts.map +1 -0
- package/lib/typescript/core/WorkletProcessingNode.d.ts +4 -0
- package/lib/typescript/core/WorkletProcessingNode.d.ts.map +1 -0
- package/lib/typescript/core/WorkletSourceNode.d.ts +4 -0
- package/lib/typescript/core/WorkletSourceNode.d.ts.map +1 -0
- package/lib/typescript/events/types.d.ts +2 -0
- package/lib/typescript/events/types.d.ts.map +1 -1
- package/lib/typescript/hooks/{useSytemVolume.d.ts → useSystemVolume.d.ts} +1 -1
- package/lib/typescript/hooks/useSystemVolume.d.ts.map +1 -0
- package/lib/typescript/interfaces.d.ts +21 -3
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +2 -1
- package/lib/typescript/types.d.ts.map +1 -1
- package/lib/typescript/utils/index.d.ts +8 -0
- package/lib/typescript/utils/index.d.ts.map +1 -1
- package/lib/typescript/web-core/AudioBufferSourceNode.d.ts +1 -1
- package/lib/typescript/web-core/AudioContext.d.ts +4 -2
- package/lib/typescript/web-core/AudioContext.d.ts.map +1 -1
- package/lib/typescript/web-core/AudioScheduledSourceNode.d.ts +1 -1
- package/lib/typescript/web-core/BaseAudioContext.d.ts +2 -0
- package/lib/typescript/web-core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/web-core/ConstantSourceNode.d.ts +8 -0
- package/lib/typescript/web-core/ConstantSourceNode.d.ts.map +1 -0
- package/lib/typescript/web-core/OfflineAudioContext.d.ts +4 -2
- package/lib/typescript/web-core/OfflineAudioContext.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/api.ts +12 -3
- package/src/api.web.ts +1 -0
- package/src/core/AudioBufferBaseSourceNode.ts +9 -9
- package/src/core/AudioBufferQueueSourceNode.ts +1 -9
- package/src/core/AudioBufferSourceNode.ts +28 -0
- package/src/core/AudioContext.ts +12 -1
- package/src/core/AudioScheduledSourceNode.ts +5 -5
- package/src/core/BaseAudioContext.ts +149 -13
- package/src/core/ConstantSourceNode.ts +13 -0
- package/src/core/OfflineAudioContext.ts +18 -2
- package/src/core/OscillatorNode.ts +11 -0
- package/src/core/WorkletNode.ts +3 -0
- package/src/core/WorkletProcessingNode.ts +3 -0
- package/src/core/WorkletSourceNode.ts +3 -0
- package/src/events/types.ts +2 -0
- package/src/interfaces.ts +59 -5
- package/src/types.ts +3 -1
- package/src/utils/index.ts +21 -0
- package/src/web-core/AudioBufferSourceNode.tsx +1 -1
- package/src/web-core/AudioContext.tsx +7 -2
- package/src/web-core/AudioScheduledSourceNode.tsx +1 -1
- package/src/web-core/BaseAudioContext.tsx +2 -0
- package/src/web-core/ConstantSourceNode.tsx +12 -0
- package/src/web-core/OfflineAudioContext.tsx +7 -2
- package/common/cpp/audioapi/HostObjects/AnalyserNodeHostObject.h +0 -149
- package/common/cpp/audioapi/HostObjects/AudioBufferBaseSourceNodeHostObject.h +0 -76
- package/common/cpp/audioapi/HostObjects/AudioBufferHostObject.h +0 -120
- package/common/cpp/audioapi/HostObjects/AudioBufferQueueSourceNodeHostObject.h +0 -67
- package/common/cpp/audioapi/HostObjects/AudioBufferSourceNodeHostObject.h +0 -142
- package/common/cpp/audioapi/HostObjects/AudioRecorderHostObject.h +0 -86
- package/common/cpp/audioapi/HostObjects/AudioScheduledSourceNodeHostObject.h +0 -56
- package/common/cpp/audioapi/HostObjects/BiquadFilterNodeHostObject.h +0 -89
- package/common/cpp/audioapi/HostObjects/GainNodeHostObject.h +0 -27
- package/common/cpp/audioapi/HostObjects/OscillatorNodeHostObject.h +0 -65
- package/common/cpp/audioapi/HostObjects/StereoPannerNodeHostObject.h +0 -29
- package/common/cpp/audioapi/HostObjects/StreamerNodeHostObject.h +0 -30
- package/common/cpp/audioapi/events/AudioEventHandlerRegistryHostObject.h +0 -48
- package/ios/audioapi/ios/events/IOSAudioEventHandlerRegistry.h +0 -7
- package/ios/audioapi/ios/events/IOSAudioEventHandlerRegistry.mm +0 -12
- package/lib/commonjs/hooks/useSytemVolume.js.map +0 -1
- package/lib/module/hooks/useSytemVolume.js.map +0 -1
- package/lib/typescript/hooks/useSytemVolume.d.ts.map +0 -1
- /package/common/cpp/audioapi/HostObjects/{AudioDestinationNodeHostObject.h → destinations/AudioDestinationNodeHostObject.h} +0 -0
- /package/common/cpp/audioapi/HostObjects/{PeriodicWaveHostObject.h → effects/PeriodicWaveHostObject.h} +0 -0
- /package/common/cpp/audioapi/core/{AudioParamEventQueue.h → utils/AudioParamEventQueue.h} +0 -0
- /package/src/hooks/{useSytemVolume.ts → useSystemVolume.ts} +0 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#include <audioapi/core/sources/WorkletSourceNode.h>
|
|
2
|
+
#include <audioapi/core/utils/Constants.h>
|
|
3
|
+
|
|
4
|
+
namespace audioapi {
|
|
5
|
+
|
|
6
|
+
WorkletSourceNode::WorkletSourceNode(
|
|
7
|
+
BaseAudioContext *context,
|
|
8
|
+
std::shared_ptr<worklets::SerializableWorklet> &worklet,
|
|
9
|
+
std::weak_ptr<worklets::WorkletRuntime> runtime)
|
|
10
|
+
: AudioScheduledSourceNode(context),
|
|
11
|
+
workletRunner_(runtime),
|
|
12
|
+
shareableWorklet_(worklet) {
|
|
13
|
+
isInitialized_ = true;
|
|
14
|
+
|
|
15
|
+
// Prepare buffers for audio processing
|
|
16
|
+
size_t outputChannelCount = this->getChannelCount();
|
|
17
|
+
outputBuffsHandles_.resize(outputChannelCount);
|
|
18
|
+
for (size_t i = 0; i < outputChannelCount; ++i) {
|
|
19
|
+
auto buff = new uint8_t[RENDER_QUANTUM_SIZE * sizeof(float)];
|
|
20
|
+
outputBuffsHandles_[i] = std::make_shared<AudioArrayBuffer>(
|
|
21
|
+
buff, RENDER_QUANTUM_SIZE * sizeof(float));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
std::shared_ptr<AudioBus> WorkletSourceNode::processNode(
|
|
26
|
+
const std::shared_ptr<AudioBus> &processingBus,
|
|
27
|
+
int framesToProcess) {
|
|
28
|
+
if (isUnscheduled() || isFinished() || !isEnabled()) {
|
|
29
|
+
processingBus->zero();
|
|
30
|
+
return processingBus;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
size_t startOffset = 0;
|
|
34
|
+
size_t nonSilentFramesToProcess = framesToProcess;
|
|
35
|
+
|
|
36
|
+
updatePlaybackInfo(
|
|
37
|
+
processingBus, framesToProcess, startOffset, nonSilentFramesToProcess);
|
|
38
|
+
|
|
39
|
+
if (nonSilentFramesToProcess == 0) {
|
|
40
|
+
processingBus->zero();
|
|
41
|
+
return processingBus;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
size_t outputChannelCount = processingBus->getNumberOfChannels();
|
|
45
|
+
|
|
46
|
+
auto result = workletRunner_.executeOnRuntimeGuardedSync(
|
|
47
|
+
[this, nonSilentFramesToProcess, startOffset](jsi::Runtime &rt) {
|
|
48
|
+
auto jsiArray = jsi::Array(rt, this->outputBuffsHandles_.size());
|
|
49
|
+
for (size_t i = 0; i < this->outputBuffsHandles_.size(); ++i) {
|
|
50
|
+
auto arrayBuffer = jsi::ArrayBuffer(rt, this->outputBuffsHandles_[i]);
|
|
51
|
+
jsiArray.setValueAtIndex(rt, i, arrayBuffer);
|
|
52
|
+
}
|
|
53
|
+
return workletRunner_
|
|
54
|
+
.executeWorklet(
|
|
55
|
+
shareableWorklet_,
|
|
56
|
+
jsiArray,
|
|
57
|
+
jsi::Value(rt, static_cast<int>(nonSilentFramesToProcess)),
|
|
58
|
+
jsi::Value(rt, this->context_->getCurrentTime()),
|
|
59
|
+
jsi::Value(rt, static_cast<int>(startOffset)))
|
|
60
|
+
.value_or(jsi::Value::undefined());
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// If the worklet execution failed, zero the output
|
|
64
|
+
// It might happen if the runtime is not available
|
|
65
|
+
if (!result.has_value()) {
|
|
66
|
+
processingBus->zero();
|
|
67
|
+
return processingBus;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Copy the processed data back to the AudioBus
|
|
71
|
+
for (size_t i = 0; i < outputChannelCount; ++i) {
|
|
72
|
+
float *channelData = processingBus->getChannel(i)->getData();
|
|
73
|
+
memcpy(
|
|
74
|
+
channelData + startOffset,
|
|
75
|
+
outputBuffsHandles_[i]->data(),
|
|
76
|
+
nonSilentFramesToProcess * sizeof(float));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
handleStopScheduled();
|
|
80
|
+
|
|
81
|
+
return processingBus;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
} // namespace audioapi
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <jsi/jsi.h>
|
|
3
|
+
#include <audioapi/core/BaseAudioContext.h>
|
|
4
|
+
#include <audioapi/utils/AudioBus.h>
|
|
5
|
+
#include <audioapi/core/sources/AudioScheduledSourceNode.h>
|
|
6
|
+
#include <audioapi/core/utils/worklets/SafeIncludes.h>
|
|
7
|
+
#include <audioapi/core/utils/worklets/WorkletsRunner.h>
|
|
8
|
+
#include <audioapi/jsi/AudioArrayBuffer.h>
|
|
9
|
+
#include <audioapi/utils/AudioArray.h>
|
|
10
|
+
|
|
11
|
+
#include <vector>
|
|
12
|
+
#include <memory>
|
|
13
|
+
|
|
14
|
+
namespace audioapi {
|
|
15
|
+
|
|
16
|
+
#if RN_AUDIO_API_TEST
|
|
17
|
+
class WorkletSourceNode : public AudioScheduledSourceNode {
|
|
18
|
+
public:
|
|
19
|
+
explicit WorkletSourceNode(
|
|
20
|
+
BaseAudioContext *context,
|
|
21
|
+
std::shared_ptr<worklets::SerializableWorklet> &worklet,
|
|
22
|
+
std::weak_ptr<worklets::WorkletRuntime> runtime
|
|
23
|
+
) : AudioScheduledSourceNode(context) {}
|
|
24
|
+
|
|
25
|
+
protected:
|
|
26
|
+
std::shared_ptr<AudioBus> processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override { return processingBus; }
|
|
27
|
+
};
|
|
28
|
+
#else
|
|
29
|
+
|
|
30
|
+
class WorkletSourceNode : public AudioScheduledSourceNode {
|
|
31
|
+
public:
|
|
32
|
+
explicit WorkletSourceNode(
|
|
33
|
+
BaseAudioContext *context,
|
|
34
|
+
std::shared_ptr<worklets::SerializableWorklet> &worklet,
|
|
35
|
+
std::weak_ptr<worklets::WorkletRuntime> runtime
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
protected:
|
|
39
|
+
std::shared_ptr<AudioBus> processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
|
|
40
|
+
private:
|
|
41
|
+
WorkletsRunner workletRunner_;
|
|
42
|
+
std::shared_ptr<worklets::SerializableWorklet> shareableWorklet_;
|
|
43
|
+
std::vector<std::shared_ptr<AudioArrayBuffer>> outputBuffsHandles_;
|
|
44
|
+
};
|
|
45
|
+
#endif // RN_AUDIO_API_TEST
|
|
46
|
+
|
|
47
|
+
} // namespace audioapi
|
package/common/cpp/audioapi/core/{AudioParamEventQueue.cpp → utils/AudioParamEventQueue.cpp}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#include <audioapi/core/AudioParamEventQueue.h>
|
|
1
|
+
#include <audioapi/core/utils/AudioParamEventQueue.h>
|
|
2
2
|
|
|
3
3
|
namespace audioapi {
|
|
4
4
|
|
|
@@ -31,12 +31,12 @@ bool AudioParamEventQueue::popFront(ParamChangeEvent &event) {
|
|
|
31
31
|
|
|
32
32
|
void AudioParamEventQueue::cancelScheduledValues(double cancelTime) {
|
|
33
33
|
while (!eventQueue_.isEmpty()) {
|
|
34
|
-
auto &
|
|
35
|
-
if (
|
|
34
|
+
auto &back = eventQueue_.peekBack();
|
|
35
|
+
if (back.getEndTime() < cancelTime) {
|
|
36
36
|
break;
|
|
37
37
|
}
|
|
38
|
-
if (
|
|
39
|
-
|
|
38
|
+
if (back.getStartTime() >= cancelTime ||
|
|
39
|
+
back.getType() == ParamChangeEventType::SET_VALUE_CURVE) {
|
|
40
40
|
eventQueue_.popBack();
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -46,8 +46,8 @@ void AudioParamEventQueue::cancelAndHoldAtTime(
|
|
|
46
46
|
double cancelTime,
|
|
47
47
|
double &endTimeCache) {
|
|
48
48
|
while (!eventQueue_.isEmpty()) {
|
|
49
|
-
auto &
|
|
50
|
-
if (
|
|
49
|
+
auto &back = eventQueue_.peekBack();
|
|
50
|
+
if (back.getEndTime() < cancelTime || back.getStartTime() <= cancelTime) {
|
|
51
51
|
break;
|
|
52
52
|
}
|
|
53
53
|
eventQueue_.popBack();
|
|
@@ -59,6 +59,12 @@ void AudioParamEventQueue::cancelAndHoldAtTime(
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
auto &back = eventQueue_.peekBackMut();
|
|
62
|
+
back.setEndValue(back.getCalculateValue()(
|
|
63
|
+
back.getStartTime(),
|
|
64
|
+
back.getEndTime(),
|
|
65
|
+
back.getStartValue(),
|
|
66
|
+
back.getEndValue(),
|
|
67
|
+
cancelTime));
|
|
62
68
|
back.setEndTime(std::min(cancelTime, back.getEndTime()));
|
|
63
69
|
}
|
|
64
70
|
|
|
@@ -16,4 +16,9 @@ static constexpr float MOST_NEGATIVE_SINGLE_FLOAT = static_cast<float>(std::nume
|
|
|
16
16
|
static float LOG2_MOST_POSITIVE_SINGLE_FLOAT = std::log2(MOST_POSITIVE_SINGLE_FLOAT);
|
|
17
17
|
static float LOG10_MOST_POSITIVE_SINGLE_FLOAT = std::log10(MOST_POSITIVE_SINGLE_FLOAT);
|
|
18
18
|
static constexpr float PI = static_cast<float>(M_PI);
|
|
19
|
+
|
|
20
|
+
// buffer sizes
|
|
21
|
+
static constexpr size_t PROMISE_VENDOR_THREAD_POOL_WORKER_COUNT = 4;
|
|
22
|
+
static constexpr size_t PROMISE_VENDOR_THREAD_POOL_LOAD_BALANCER_QUEUE_SIZE = 32;
|
|
23
|
+
static constexpr size_t PROMISE_VENDOR_THREAD_POOL_WORKER_QUEUE_SIZE = 32;
|
|
19
24
|
} // namespace audioapi
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <jsi/jsi.h>
|
|
4
|
+
|
|
5
|
+
#include <string>
|
|
6
|
+
#include <memory>
|
|
7
|
+
|
|
8
|
+
#ifdef __APPLE__
|
|
9
|
+
/// We cannot make any conditional logic inside podspec but it should automatically compile those files
|
|
10
|
+
/// they should be accessible if someone has react-native-worklets in node_modules
|
|
11
|
+
#if __has_include(<worklets/WorkletRuntime/WorkletRuntime.h>)
|
|
12
|
+
#define RN_AUDIO_API_ENABLE_WORKLETS 1
|
|
13
|
+
#else
|
|
14
|
+
#define RN_AUDIO_API_ENABLE_WORKLETS 0
|
|
15
|
+
#endif
|
|
16
|
+
#endif
|
|
17
|
+
|
|
18
|
+
#ifndef RN_AUDIO_API_TEST
|
|
19
|
+
#define RN_AUDIO_API_TEST 0
|
|
20
|
+
#endif
|
|
21
|
+
|
|
22
|
+
#if RN_AUDIO_API_ENABLE_WORKLETS
|
|
23
|
+
#include <worklets/WorkletRuntime/WorkletRuntime.h>
|
|
24
|
+
#include <worklets/SharedItems/Serializable.h>
|
|
25
|
+
#include <worklets/NativeModules/WorkletsModuleProxy.h>
|
|
26
|
+
#if ANDROID
|
|
27
|
+
#include <worklets/android/WorkletsModule.h>
|
|
28
|
+
#endif
|
|
29
|
+
#else
|
|
30
|
+
/// @brief Dummy implementation of worklets for non-worklet builds they should do nothing and mock necessary methods
|
|
31
|
+
/// @note It helps to reduce compile time branching across codebase
|
|
32
|
+
/// @note If you need to base some c++ implementation on if the worklets are enabled use `#if RN_AUDIO_API_ENABLE_WORKLETS`
|
|
33
|
+
namespace worklets {
|
|
34
|
+
|
|
35
|
+
using namespace facebook;
|
|
36
|
+
class MessageQueueThread {};
|
|
37
|
+
class WorkletsModuleProxy {};
|
|
38
|
+
class WorkletRuntime {
|
|
39
|
+
explicit WorkletRuntime(uint64_t, const std::shared_ptr<MessageQueueThread> &, const std::string &, const bool);
|
|
40
|
+
};
|
|
41
|
+
class SerializableWorklet {
|
|
42
|
+
SerializableWorklet(jsi::Runtime*, const jsi::Object &);
|
|
43
|
+
};
|
|
44
|
+
} // namespace worklets
|
|
45
|
+
#endif
|
|
46
|
+
|
|
47
|
+
/// @brief Struct to hold references to different runtimes used in the AudioAPI
|
|
48
|
+
/// @note it is used to pass them around and avoid creating multiple instances of the same runtime
|
|
49
|
+
struct RuntimeRegistry {
|
|
50
|
+
std::weak_ptr<worklets::WorkletRuntime> uiRuntime;
|
|
51
|
+
std::weak_ptr<worklets::WorkletRuntime> audioRuntime;
|
|
52
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <jsi/jsi.h>
|
|
4
|
+
#include <audioapi/core/utils/worklets/SafeIncludes.h>
|
|
5
|
+
|
|
6
|
+
#include <functional>
|
|
7
|
+
#include <atomic>
|
|
8
|
+
#include <memory>
|
|
9
|
+
#include <utility>
|
|
10
|
+
#include <optional>
|
|
11
|
+
|
|
12
|
+
namespace audioapi {
|
|
13
|
+
using namespace facebook;
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
* # How to extract worklet from JavaScript argument
|
|
17
|
+
*
|
|
18
|
+
* To extract a shareable worklet from a JavaScript argument, use the following code:
|
|
19
|
+
*
|
|
20
|
+
* ```cpp
|
|
21
|
+
* auto worklet = worklets::extractSerializableWorkletFromArg(runtime, args[0]);
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* This will return a shared pointer to the extracted worklet, or throw an error if the argument is invalid.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
class WorkletsRunner {
|
|
28
|
+
public:
|
|
29
|
+
explicit WorkletsRunner(std::weak_ptr<worklets::WorkletRuntime> weakUiRuntime) noexcept;
|
|
30
|
+
|
|
31
|
+
/// @brief Execute a job on the UI runtime safely.
|
|
32
|
+
/// @param job
|
|
33
|
+
/// @return nullopt if the runtime is not available or the result of the job execution
|
|
34
|
+
/// @note Execution is synchronous
|
|
35
|
+
std::optional<jsi::Value> executeOnRuntimeGuardedSync(const std::function<jsi::Value(jsi::Runtime&)>&& job) const noexcept(noexcept(job)) {
|
|
36
|
+
auto strongRuntime = weakUiRuntime_.lock();
|
|
37
|
+
if (strongRuntime == nullptr) {
|
|
38
|
+
return std::nullopt;
|
|
39
|
+
}
|
|
40
|
+
#if RN_AUDIO_API_ENABLE_WORKLETS
|
|
41
|
+
return strongRuntime->executeSync(std::move(job));
|
|
42
|
+
#else
|
|
43
|
+
return std::nullopt;
|
|
44
|
+
#endif
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/// @brief Execute a worklet with the given arguments.
|
|
48
|
+
/// @tparam ...Args
|
|
49
|
+
/// @param shareableWorklet
|
|
50
|
+
/// @param ...args
|
|
51
|
+
/// @note Execution is synchronous, this method can be used in `executeOnRuntimeGuardedSync` and `...Async` methods arguments
|
|
52
|
+
/// @return nullopt if the runtime is not available or the result of the worklet execution
|
|
53
|
+
template<typename... Args>
|
|
54
|
+
std::optional<jsi::Value> executeWorklet(const std::shared_ptr<worklets::SerializableWorklet>& shareableWorklet, Args&&... args) {
|
|
55
|
+
auto strongRuntime = weakUiRuntime_.lock();
|
|
56
|
+
if (strongRuntime == nullptr) {
|
|
57
|
+
return std::nullopt;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
#if RN_AUDIO_API_ENABLE_WORKLETS
|
|
61
|
+
|
|
62
|
+
return strongRuntime->runGuarded(shareableWorklet, std::forward<Args>(args)...);
|
|
63
|
+
|
|
64
|
+
#else
|
|
65
|
+
return std::nullopt;
|
|
66
|
+
#endif
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private:
|
|
70
|
+
std::weak_ptr<worklets::WorkletRuntime> weakUiRuntime_;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
} // namespace audioapi
|
|
@@ -53,8 +53,9 @@ class AudioEventHandlerRegistry : public IAudioEventHandlerRegistry {
|
|
|
53
53
|
"volumeChange",
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
-
static constexpr std::array<std::string_view,
|
|
56
|
+
static constexpr std::array<std::string_view, 6> AUDIO_API_EVENT_NAMES = {
|
|
57
57
|
"ended",
|
|
58
|
+
"loopEnded",
|
|
58
59
|
"audioReady",
|
|
59
60
|
"positionChanged",
|
|
60
61
|
"audioError",
|
|
@@ -9,7 +9,20 @@ using namespace facebook;
|
|
|
9
9
|
class AudioArrayBuffer : public jsi::MutableBuffer {
|
|
10
10
|
public:
|
|
11
11
|
AudioArrayBuffer(uint8_t *data, size_t size): data_(data), size_(size) {}
|
|
12
|
-
~AudioArrayBuffer() override
|
|
12
|
+
~AudioArrayBuffer() override {
|
|
13
|
+
if (data_ == nullptr) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
delete[] data_;
|
|
17
|
+
}
|
|
18
|
+
AudioArrayBuffer(AudioArrayBuffer &&other) noexcept
|
|
19
|
+
: data_(other.data_), size_(other.size_) {
|
|
20
|
+
other.data_ = nullptr;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
AudioArrayBuffer(const AudioArrayBuffer &) = delete;
|
|
24
|
+
AudioArrayBuffer &operator=(const AudioArrayBuffer &) = delete;
|
|
25
|
+
AudioArrayBuffer &operator=(AudioArrayBuffer &&other) = delete;
|
|
13
26
|
|
|
14
27
|
[[nodiscard]] size_t size() const override;
|
|
15
28
|
uint8_t *data() override;
|
|
@@ -10,13 +10,8 @@
|
|
|
10
10
|
#include <utility>
|
|
11
11
|
#include <vector>
|
|
12
12
|
|
|
13
|
-
#define
|
|
14
|
-
|
|
15
|
-
jsi::Runtime &runtime, \
|
|
16
|
-
const jsi::Value &thisValue, \
|
|
17
|
-
const jsi::Value *args, \
|
|
18
|
-
size_t count)
|
|
19
|
-
|
|
13
|
+
#define JSI_HOST_FUNCTION_DECL(name) jsi::Value name(jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *args, size_t count)
|
|
14
|
+
#define JSI_HOST_FUNCTION_IMPL(CLASS, name) jsi::Value CLASS::name(jsi::Runtime &runtime, const jsi::Value &thisValue, const jsi::Value *args, size_t count)
|
|
20
15
|
#define JSI_EXPORT_FUNCTION(CLASS, FUNCTION) \
|
|
21
16
|
std::make_pair( \
|
|
22
17
|
std::string(#FUNCTION), \
|
|
@@ -24,17 +19,16 @@
|
|
|
24
19
|
jsi::Runtime &, const jsi::Value &, const jsi::Value *, size_t)>( \
|
|
25
20
|
&CLASS::FUNCTION))
|
|
26
21
|
|
|
27
|
-
#define
|
|
28
|
-
|
|
22
|
+
#define JSI_PROPERTY_GETTER_DECL(name) jsi::Value name(jsi::Runtime &runtime)
|
|
23
|
+
#define JSI_PROPERTY_GETTER_IMPL(CLASS, name) jsi::Value CLASS::name(jsi::Runtime &runtime)
|
|
29
24
|
#define JSI_EXPORT_PROPERTY_GETTER(CLASS, FUNCTION) \
|
|
30
25
|
std::make_pair( \
|
|
31
26
|
std::string(#FUNCTION), \
|
|
32
27
|
static_cast<jsi::Value (JsiHostObject::*)(jsi::Runtime &)>( \
|
|
33
28
|
&CLASS::FUNCTION))
|
|
34
29
|
|
|
35
|
-
#define
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
#define JSI_PROPERTY_SETTER_DECL(name) void name(jsi::Runtime &runtime, const jsi::Value &value)
|
|
31
|
+
#define JSI_PROPERTY_SETTER_IMPL(CLASS, name) void CLASS::name(jsi::Runtime &runtime, const jsi::Value &value)
|
|
38
32
|
#define JSI_EXPORT_PROPERTY_SETTER(CLASS, FUNCTION) \
|
|
39
33
|
std::make_pair( \
|
|
40
34
|
std::string(#FUNCTION), \
|
|
@@ -61,4 +61,53 @@ jsi::Value PromiseVendor::createPromise(
|
|
|
61
61
|
return promiseCtor.callAsConstructor(runtime, runPromise);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
jsi::Value PromiseVendor::createAsyncPromise(
|
|
65
|
+
std::function<std::variant<jsi::Value, std::string>(jsi::Runtime &)>
|
|
66
|
+
&&function) {
|
|
67
|
+
auto &runtime = *runtime_;
|
|
68
|
+
auto callInvoker = callInvoker_;
|
|
69
|
+
auto threadPool = threadPool_;
|
|
70
|
+
auto promiseCtor = runtime.global().getPropertyAsFunction(runtime, "Promise");
|
|
71
|
+
auto promiseLambda = [threadPool = std::move(threadPool),
|
|
72
|
+
callInvoker = std::move(callInvoker),
|
|
73
|
+
function = std::move(function)](
|
|
74
|
+
jsi::Runtime &runtime,
|
|
75
|
+
const jsi::Value &thisValue,
|
|
76
|
+
const jsi::Value *arguments,
|
|
77
|
+
size_t count) -> jsi::Value {
|
|
78
|
+
auto resolveLocal = arguments[0].asObject(runtime).asFunction(runtime);
|
|
79
|
+
auto resolve = std::make_shared<jsi::Function>(std::move(resolveLocal));
|
|
80
|
+
auto rejectLocal = arguments[1].asObject(runtime).asFunction(runtime);
|
|
81
|
+
auto reject = std::make_shared<jsi::Function>(std::move(rejectLocal));
|
|
82
|
+
|
|
83
|
+
threadPool->schedule([callInvoker = std::move(callInvoker),
|
|
84
|
+
function = std::move(function),
|
|
85
|
+
resolve = std::move(resolve),
|
|
86
|
+
reject = std::move(reject),
|
|
87
|
+
&runtime]() {
|
|
88
|
+
auto result = function(runtime);
|
|
89
|
+
if (std::holds_alternative<jsi::Value>(result)) {
|
|
90
|
+
auto valueShared = std::make_shared<jsi::Value>(
|
|
91
|
+
std::move(std::get<jsi::Value>(result)));
|
|
92
|
+
callInvoker->invokeAsync([resolve, &runtime, valueShared]() -> void {
|
|
93
|
+
resolve->call(runtime, *valueShared);
|
|
94
|
+
});
|
|
95
|
+
} else {
|
|
96
|
+
auto errorMessage = std::get<std::string>(result);
|
|
97
|
+
callInvoker->invokeAsync([reject, &runtime, errorMessage]() -> void {
|
|
98
|
+
auto error = jsi::JSError(runtime, errorMessage);
|
|
99
|
+
reject->call(runtime, error.value());
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
return jsi::Value::undefined();
|
|
104
|
+
};
|
|
105
|
+
auto promiseFunction = jsi::Function::createFromHostFunction(
|
|
106
|
+
runtime,
|
|
107
|
+
jsi::PropNameID::forUtf8(runtime, "asyncPromise"),
|
|
108
|
+
2,
|
|
109
|
+
std::move(promiseLambda));
|
|
110
|
+
return promiseCtor.callAsConstructor(runtime, std::move(promiseFunction));
|
|
111
|
+
}
|
|
112
|
+
|
|
64
113
|
} // namespace audioapi
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
#include <audioapi/core/utils/Constants.h>
|
|
3
5
|
#include <ReactCommon/CallInvoker.h>
|
|
4
6
|
#include <jsi/jsi.h>
|
|
7
|
+
#include <variant>
|
|
8
|
+
#include <thread>
|
|
5
9
|
#include <memory>
|
|
6
10
|
#include <string>
|
|
7
11
|
#include <utility>
|
|
8
12
|
#include <functional>
|
|
13
|
+
#include <audioapi/utils/ThreadPool.hpp>
|
|
9
14
|
|
|
10
15
|
namespace audioapi {
|
|
11
16
|
|
|
@@ -30,13 +35,36 @@ class Promise {
|
|
|
30
35
|
|
|
31
36
|
class PromiseVendor {
|
|
32
37
|
public:
|
|
33
|
-
PromiseVendor(jsi::Runtime *runtime, const std::shared_ptr<react::CallInvoker> &callInvoker):
|
|
38
|
+
PromiseVendor(jsi::Runtime *runtime, const std::shared_ptr<react::CallInvoker> &callInvoker):
|
|
39
|
+
runtime_(runtime), callInvoker_(callInvoker), threadPool_(std::make_shared<ThreadPool>(
|
|
40
|
+
audioapi::PROMISE_VENDOR_THREAD_POOL_WORKER_COUNT,
|
|
41
|
+
audioapi::PROMISE_VENDOR_THREAD_POOL_LOAD_BALANCER_QUEUE_SIZE,
|
|
42
|
+
audioapi::PROMISE_VENDOR_THREAD_POOL_WORKER_QUEUE_SIZE)) {}
|
|
34
43
|
|
|
35
44
|
jsi::Value createPromise(const std::function<void(std::shared_ptr<Promise>)> &function);
|
|
36
45
|
|
|
46
|
+
/// @brief Creates an asynchronous promise.
|
|
47
|
+
/// @param function The function to execute asynchronously. It should return either a jsi::Value on success or a std::string error message on failure.
|
|
48
|
+
/// @return The created promise.
|
|
49
|
+
/// @note The function is executed on a different thread, and the promise is resolved or rejected based on the function's outcome.
|
|
50
|
+
/// @note IMPORTANT: This function is not thread-safe and should be called from a single thread only. (comes from underlying ThreadPool implementation)
|
|
51
|
+
/// @example
|
|
52
|
+
/// ```cpp
|
|
53
|
+
/// auto promise = promiseVendor_->createAsyncPromise(
|
|
54
|
+
/// [](jsi::Runtime& rt) -> std::variant<jsi::Value, std::string> {
|
|
55
|
+
/// // Simulate some heavy work
|
|
56
|
+
/// std::this_thread::sleep_for(std::chrono::seconds(2));
|
|
57
|
+
/// return jsi::String::createFromUtf8(rt, "Promise resolved successfully!");
|
|
58
|
+
/// }
|
|
59
|
+
/// );
|
|
60
|
+
///
|
|
61
|
+
/// return promise;
|
|
62
|
+
jsi::Value createAsyncPromise(std::function<std::variant<jsi::Value, std::string>(jsi::Runtime&)> &&function);
|
|
63
|
+
|
|
37
64
|
private:
|
|
38
65
|
jsi::Runtime *runtime_;
|
|
39
66
|
std::shared_ptr<react::CallInvoker> callInvoker_;
|
|
67
|
+
std::shared_ptr<ThreadPool> threadPool_;
|
|
40
68
|
};
|
|
41
69
|
|
|
42
70
|
} // namespace audioapi
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <thread>
|
|
3
|
+
#include <vector>
|
|
4
|
+
#include <functional>
|
|
5
|
+
#include <variant>
|
|
6
|
+
#include <audioapi/utils/SpscChannel.hpp>
|
|
7
|
+
|
|
8
|
+
namespace audioapi {
|
|
9
|
+
|
|
10
|
+
/// @brief A simple thread pool implementation using lock-free SPSC channels for task scheduling and execution.
|
|
11
|
+
/// @note The thread pool consists of a load balancer thread and multiple worker threads.
|
|
12
|
+
/// @note The load balancer receives tasks and distributes them to worker threads in a round-robin fashion.
|
|
13
|
+
/// @note Each worker thread has its own SPSC channel to receive tasks from the load balancer.
|
|
14
|
+
/// @note The thread pool can be shut down gracefully by sending a stop event to the load balancer, which then propagates the stop event to all worker threads.
|
|
15
|
+
/// @note IMPORTANT: ThreadPool is not thread-safe and events should be scheduled from a single thread only.
|
|
16
|
+
class ThreadPool {
|
|
17
|
+
struct StopEvent {};
|
|
18
|
+
struct TaskEvent { std::function<void()> task; };
|
|
19
|
+
using Event = std::variant<TaskEvent, StopEvent>;
|
|
20
|
+
|
|
21
|
+
using Sender = channels::spsc::Sender<Event, channels::spsc::OverflowStrategy::WAIT_ON_FULL, channels::spsc::WaitStrategy::ATOMIC_WAIT>;
|
|
22
|
+
using Receiver = channels::spsc::Receiver<Event, channels::spsc::OverflowStrategy::WAIT_ON_FULL, channels::spsc::WaitStrategy::ATOMIC_WAIT>;
|
|
23
|
+
public:
|
|
24
|
+
/// @brief Construct a new ThreadPool
|
|
25
|
+
/// @param numThreads The number of worker threads to create
|
|
26
|
+
/// @param loadBalancerQueueSize The size of the load balancer's queue
|
|
27
|
+
/// @param workerQueueSize The size of each worker thread's queue
|
|
28
|
+
ThreadPool(size_t numThreads, size_t loadBalancerQueueSize = 32, size_t workerQueueSize = 32) {
|
|
29
|
+
auto [sender, receiver] = channels::spsc::channel<Event, channels::spsc::OverflowStrategy::WAIT_ON_FULL, channels::spsc::WaitStrategy::ATOMIC_WAIT>(loadBalancerQueueSize);
|
|
30
|
+
loadBalancerSender = std::move(sender);
|
|
31
|
+
std::vector<Sender> workerSenders;
|
|
32
|
+
workerSenders.reserve(numThreads);
|
|
33
|
+
for (size_t i = 0; i < numThreads; ++i) {
|
|
34
|
+
auto [workerSender, workerReceiver] = channels::spsc::channel<Event, channels::spsc::OverflowStrategy::WAIT_ON_FULL, channels::spsc::WaitStrategy::ATOMIC_WAIT>(workerQueueSize);
|
|
35
|
+
workers.emplace_back(&ThreadPool::workerThreadFunc, this, std::move(workerReceiver));
|
|
36
|
+
workerSenders.emplace_back(std::move(workerSender));
|
|
37
|
+
}
|
|
38
|
+
loadBalancerThread = std::thread(&ThreadPool::loadBalancerThreadFunc, this, std::move(receiver), std::move(workerSenders));
|
|
39
|
+
}
|
|
40
|
+
~ThreadPool() {
|
|
41
|
+
loadBalancerSender.send(StopEvent{});
|
|
42
|
+
loadBalancerThread.join();
|
|
43
|
+
for (auto& worker : workers) {
|
|
44
|
+
worker.join();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/// @brief Schedule a task to be executed by the thread pool
|
|
49
|
+
/// @param task The task to be executed
|
|
50
|
+
/// @note This function is lock-free and most of the time wait-free, but may block if the load balancer queue is full.
|
|
51
|
+
/// @note Please remember that the task will be executed in a different thread, so make sure to capture any required variables by value.
|
|
52
|
+
/// @note The task should not throw exceptions, as they will not be caught.
|
|
53
|
+
/// @note The task should end at some point, otherwise the thread pool will never be able to shut down.
|
|
54
|
+
/// @note IMPORTANT: This function is not thread-safe and should be called from a single thread only.
|
|
55
|
+
void schedule(std::function<void()> &&task) noexcept {
|
|
56
|
+
loadBalancerSender.send(TaskEvent{std::move(task)});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private:
|
|
60
|
+
std::thread loadBalancerThread;
|
|
61
|
+
std::vector<std::thread> workers;
|
|
62
|
+
Sender loadBalancerSender;
|
|
63
|
+
|
|
64
|
+
void workerThreadFunc(Receiver &&receiver) {
|
|
65
|
+
Receiver localReceiver = std::move(receiver);
|
|
66
|
+
while (true) {
|
|
67
|
+
auto event = localReceiver.receive();
|
|
68
|
+
/// We use [[unlikely]] and [[likely]] attributes to help the compiler optimize the branching.
|
|
69
|
+
/// we expect most of the time to receive TaskEvent, and rarely StopEvent.
|
|
70
|
+
/// and whenever we receive StopEvent we can burn some cycles as it will not be expected to execute fast.
|
|
71
|
+
if (std::holds_alternative<StopEvent>(event)) [[ unlikely ]] {
|
|
72
|
+
break;
|
|
73
|
+
} else if (std::holds_alternative<TaskEvent>(event)) [[ likely ]] {
|
|
74
|
+
std::get<TaskEvent>(event).task();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
void loadBalancerThreadFunc(Receiver &&receiver, std::vector<Sender> &&workerSenders) {
|
|
80
|
+
Receiver localReceiver = std::move(receiver);
|
|
81
|
+
std::vector<Sender> localWorkerSenders = std::move(workerSenders);
|
|
82
|
+
size_t nextWorker = 0;
|
|
83
|
+
while (true) {
|
|
84
|
+
auto event = localReceiver.receive();
|
|
85
|
+
/// We use [[unlikely]] and [[likely]] attributes to help the compiler optimize the branching.
|
|
86
|
+
/// we expect most of the time to receive TaskEvent, and rarely StopEvent.
|
|
87
|
+
/// and whenever we receive StopEvent we can burn some cycles as it will not be expected to execute fast.
|
|
88
|
+
if (std::holds_alternative<StopEvent>(event)) [[ unlikely ]] {
|
|
89
|
+
// Propagate stop event to all workers
|
|
90
|
+
for (size_t i = 0; i < localWorkerSenders.size(); ++i) {
|
|
91
|
+
localWorkerSenders[i].send(StopEvent{});
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
} else if (std::holds_alternative<TaskEvent>(event)) [[ likely ]] {
|
|
95
|
+
// Dispatch task to the next worker in round-robin fashion
|
|
96
|
+
auto& taskEvent = std::get<TaskEvent>(event);
|
|
97
|
+
localWorkerSenders[nextWorker].send(std::move(taskEvent));
|
|
98
|
+
nextWorker = (nextWorker + 1) % localWorkerSenders.size();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
}; // namespace audioapi
|