react-native-audio-api 0.13.0-nightly-51a651d-20260701 → 0.13.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.
- package/android/build.gradle +1 -0
- package/android/src/main/cpp/audioapi/android/AudioAPIModule.cpp +4 -0
- package/android/src/main/cpp/audioapi/android/core/utils/AndroidFileWriterBackend.cpp +2 -2
- package/android/src/main/cpp/audioapi/android/core/utils/AndroidRotatingFileWriter.cpp +3 -1
- package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/FFmpegFileWriter.cpp +7 -3
- package/android/src/main/cpp/audioapi/android/core/utils/miniaudioBackend/MiniAudioFileWriter.cpp +3 -3
- package/android/src/main/cpp/audioapi/android/system/NativeFileInfo.cpp +48 -0
- package/android/src/main/cpp/audioapi/android/system/NativeFileInfo.hpp +6 -8
- package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +2 -0
- package/android/src/oldarch/NativeAudioAPIModuleSpec.java +4 -0
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +1 -1
- package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.cpp +1 -24
- package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.h +0 -1
- package/common/cpp/audioapi/HostObjects/utils/AudioFileUtilsHostObject.cpp +55 -47
- package/common/cpp/audioapi/HostObjects/utils/NodeOptionsParser.h +60 -6
- package/common/cpp/audioapi/core/BaseAudioContext.cpp +1 -1
- package/common/cpp/audioapi/core/sources/AudioFileSourceNode.cpp +7 -2
- package/common/cpp/audioapi/core/utils/AudioDecoding.cpp +69 -25
- package/common/cpp/audioapi/core/utils/{AudioDecoding.hpp → AudioDecoding.h} +18 -13
- package/common/cpp/audioapi/core/utils/decoding/SeekDecoderDaemon.cpp +4 -4
- package/common/cpp/audioapi/core/utils/decoding/SeekDecoderDaemon.h +3 -0
- package/common/cpp/audioapi/libs/decoding/IncrementalAudioDecoder.h +11 -0
- package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp +72 -48
- package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.h +10 -1
- package/common/cpp/audioapi/libs/miniaudio/MiniAudioDecoding.cpp +7 -0
- package/common/cpp/audioapi/libs/miniaudio/MiniAudioDecoding.h +5 -0
- package/common/cpp/audioapi/types/NodeOptions.h +3 -0
- package/common/cpp/audioapi/utils/TaskOffloader.hpp +43 -11
- package/ios/audioapi/ios/AudioAPIModule.mm +9 -0
- package/ios/audioapi/ios/core/utils/IOSFileWriter.mm +6 -3
- package/ios/audioapi/ios/core/utils/IOSRotatingFileWriter.mm +3 -1
- package/lib/commonjs/Audio/Audio.js +2 -0
- package/lib/commonjs/Audio/Audio.js.map +1 -1
- package/lib/commonjs/Audio/useAudioSourceLoader.js +15 -11
- package/lib/commonjs/Audio/useAudioSourceLoader.js.map +1 -1
- package/lib/commonjs/Audio/utils.js +4 -1
- package/lib/commonjs/Audio/utils.js.map +1 -1
- package/lib/commonjs/api.js +10 -2
- package/lib/commonjs/api.js.map +1 -1
- package/lib/commonjs/api.web.js +6 -0
- package/lib/commonjs/api.web.js.map +1 -1
- package/lib/commonjs/core/AudioDecoder.js +1 -32
- package/lib/commonjs/core/AudioDecoder.js.map +1 -1
- package/lib/commonjs/core/AudioFileUtils.js +32 -11
- package/lib/commonjs/core/AudioFileUtils.js.map +1 -1
- package/lib/commonjs/mock/index.js +5 -5
- package/lib/commonjs/mock/index.js.map +1 -1
- package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -1
- package/lib/commonjs/specs/NativeAudioAPIModule.web.js +1 -0
- package/lib/commonjs/specs/NativeAudioAPIModule.web.js.map +1 -1
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/utils/flags.js +18 -0
- package/lib/commonjs/utils/flags.js.map +1 -0
- package/lib/commonjs/utils/index.js +24 -0
- package/lib/commonjs/utils/index.js.map +1 -1
- package/lib/commonjs/utils/paths.js +9 -0
- package/lib/commonjs/utils/paths.js.map +1 -1
- package/lib/commonjs/utils/remoteHttpSource.js +80 -0
- package/lib/commonjs/utils/remoteHttpSource.js.map +1 -0
- package/lib/commonjs/web-core/AudioBufferSourceNode.web.js +7 -1
- package/lib/commonjs/web-core/AudioBufferSourceNode.web.js.map +1 -1
- package/lib/commonjs/web-core/AudioContext.web.js +2 -4
- package/lib/commonjs/web-core/AudioContext.web.js.map +1 -1
- package/lib/commonjs/web-core/AudioDecoder.web.js +6 -2
- package/lib/commonjs/web-core/AudioDecoder.web.js.map +1 -1
- package/lib/commonjs/web-core/OfflineAudioContext.web.js +2 -4
- package/lib/commonjs/web-core/OfflineAudioContext.web.js.map +1 -1
- package/lib/commonjs/web-core/custom/index.js +7 -0
- package/lib/commonjs/web-core/custom/index.js.map +1 -1
- package/lib/commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/AudioBufferSourceNodeStretcher.js +58 -6
- package/lib/commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/AudioBufferSourceNodeStretcher.js.map +1 -1
- package/lib/commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/LoadCustomWasm.js +37 -0
- package/lib/commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/LoadCustomWasm.js.map +1 -0
- package/lib/{module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.js → commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.mjs} +1 -1
- package/lib/commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.mjs.map +1 -0
- package/lib/commonjs/web-core/utils/AudioBufferSourceNodeStandard.js +8 -2
- package/lib/commonjs/web-core/utils/AudioBufferSourceNodeStandard.js.map +1 -1
- package/lib/module/Audio/Audio.js +2 -0
- package/lib/module/Audio/Audio.js.map +1 -1
- package/lib/module/Audio/useAudioSourceLoader.js +16 -12
- package/lib/module/Audio/useAudioSourceLoader.js.map +1 -1
- package/lib/module/Audio/utils.js +4 -1
- package/lib/module/Audio/utils.js.map +1 -1
- package/lib/module/api.js +3 -2
- package/lib/module/api.js.map +1 -1
- package/lib/module/api.web.js +3 -0
- package/lib/module/api.web.js.map +1 -1
- package/lib/module/core/AudioDecoder.js +2 -32
- package/lib/module/core/AudioDecoder.js.map +1 -1
- package/lib/module/core/AudioFileUtils.js +31 -11
- package/lib/module/core/AudioFileUtils.js.map +1 -1
- package/lib/module/mock/index.js +4 -5
- package/lib/module/mock/index.js.map +1 -1
- package/lib/module/specs/NativeAudioAPIModule.js.map +1 -1
- package/lib/module/specs/NativeAudioAPIModule.web.js +1 -0
- package/lib/module/specs/NativeAudioAPIModule.web.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/module/utils/flags.js +15 -0
- package/lib/module/utils/flags.js.map +1 -0
- package/lib/module/utils/index.js +17 -0
- package/lib/module/utils/index.js.map +1 -1
- package/lib/module/utils/paths.js +8 -0
- package/lib/module/utils/paths.js.map +1 -1
- package/lib/module/utils/remoteHttpSource.js +75 -0
- package/lib/module/utils/remoteHttpSource.js.map +1 -0
- package/lib/module/web-core/AudioBufferSourceNode.web.js +7 -1
- package/lib/module/web-core/AudioBufferSourceNode.web.js.map +1 -1
- package/lib/module/web-core/AudioContext.web.js +2 -4
- package/lib/module/web-core/AudioContext.web.js.map +1 -1
- package/lib/module/web-core/AudioDecoder.web.js +6 -2
- package/lib/module/web-core/AudioDecoder.web.js.map +1 -1
- package/lib/module/web-core/OfflineAudioContext.web.js +2 -4
- package/lib/module/web-core/OfflineAudioContext.web.js.map +1 -1
- package/lib/module/web-core/custom/index.js +1 -0
- package/lib/module/web-core/custom/index.js.map +1 -1
- package/lib/module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/AudioBufferSourceNodeStretcher.js +57 -6
- package/lib/module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/AudioBufferSourceNodeStretcher.js.map +1 -1
- package/lib/module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/LoadCustomWasm.js +33 -0
- package/lib/module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/LoadCustomWasm.js.map +1 -0
- package/lib/{commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.js → module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.mjs} +6 -10
- package/lib/module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.mjs.map +1 -0
- package/lib/module/web-core/utils/AudioBufferSourceNodeStandard.js +8 -2
- package/lib/module/web-core/utils/AudioBufferSourceNodeStandard.js.map +1 -1
- package/lib/typescript/Audio/Audio.d.ts.map +1 -1
- package/lib/typescript/Audio/types.d.ts +5 -0
- package/lib/typescript/Audio/types.d.ts.map +1 -1
- package/lib/typescript/Audio/useAudioSourceLoader.d.ts +2 -1
- package/lib/typescript/Audio/useAudioSourceLoader.d.ts.map +1 -1
- package/lib/typescript/Audio/utils.d.ts.map +1 -1
- package/lib/typescript/api.d.ts +3 -2
- 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/AudioDecoder.d.ts +1 -2
- package/lib/typescript/core/AudioDecoder.d.ts.map +1 -1
- package/lib/typescript/core/AudioFileUtils.d.ts +3 -3
- package/lib/typescript/core/AudioFileUtils.d.ts.map +1 -1
- package/lib/typescript/jsi-interfaces.d.ts +1 -2
- package/lib/typescript/jsi-interfaces.d.ts.map +1 -1
- package/lib/typescript/mock/index.d.ts +3 -1
- package/lib/typescript/mock/index.d.ts.map +1 -1
- package/lib/typescript/specs/NativeAudioAPIModule.d.ts +1 -0
- package/lib/typescript/specs/NativeAudioAPIModule.d.ts.map +1 -1
- package/lib/typescript/specs/NativeAudioAPIModule.web.d.ts +1 -0
- package/lib/typescript/specs/NativeAudioAPIModule.web.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/flags.d.ts +9 -0
- package/lib/typescript/utils/flags.d.ts.map +1 -0
- package/lib/typescript/utils/index.d.ts +2 -0
- package/lib/typescript/utils/index.d.ts.map +1 -1
- package/lib/typescript/utils/paths.d.ts +1 -0
- package/lib/typescript/utils/paths.d.ts.map +1 -1
- package/lib/typescript/utils/remoteHttpSource.d.ts +7 -0
- package/lib/typescript/utils/remoteHttpSource.d.ts.map +1 -0
- package/lib/typescript/web-core/AudioBufferSourceNode.web.d.ts +2 -0
- package/lib/typescript/web-core/AudioBufferSourceNode.web.d.ts.map +1 -1
- package/lib/typescript/web-core/AudioContext.web.d.ts +3 -1
- package/lib/typescript/web-core/AudioContext.web.d.ts.map +1 -1
- package/lib/typescript/web-core/AudioDecoder.web.d.ts +1 -1
- package/lib/typescript/web-core/AudioDecoder.web.d.ts.map +1 -1
- package/lib/typescript/web-core/BaseAudioContext.web.d.ts +3 -1
- package/lib/typescript/web-core/BaseAudioContext.web.d.ts.map +1 -1
- package/lib/typescript/web-core/OfflineAudioContext.web.d.ts +3 -1
- package/lib/typescript/web-core/OfflineAudioContext.web.d.ts.map +1 -1
- package/lib/typescript/web-core/custom/index.d.ts +1 -0
- package/lib/typescript/web-core/custom/index.d.ts.map +1 -1
- package/lib/typescript/web-core/custom/wasm-audio-bufffer-source-node-stretcher/AudioBufferSourceNodeStretcher.d.ts +5 -1
- package/lib/typescript/web-core/custom/wasm-audio-bufffer-source-node-stretcher/AudioBufferSourceNodeStretcher.d.ts.map +1 -1
- package/lib/typescript/web-core/custom/wasm-audio-bufffer-source-node-stretcher/LoadCustomWasm.d.ts +5 -0
- package/lib/typescript/web-core/custom/wasm-audio-bufffer-source-node-stretcher/LoadCustomWasm.d.ts.map +1 -0
- package/lib/typescript/web-core/types.web.d.ts +3 -1
- package/lib/typescript/web-core/types.web.d.ts.map +1 -1
- package/lib/typescript/web-core/utils/AudioBufferSourceNodeStandard.d.ts +2 -0
- package/lib/typescript/web-core/utils/AudioBufferSourceNodeStandard.d.ts.map +1 -1
- package/package.json +1 -1
- package/scripts/setup-rn-audio-api-web.js +4 -4
- package/src/Audio/Audio.tsx +2 -0
- package/src/Audio/types.ts +5 -0
- package/src/Audio/useAudioSourceLoader.ts +25 -15
- package/src/Audio/utils.ts +4 -0
- package/src/api.ts +3 -6
- package/src/api.web.ts +4 -0
- package/src/core/AudioDecoder.ts +3 -52
- package/src/core/AudioFileUtils.ts +66 -16
- package/src/jsi-interfaces.ts +3 -3
- package/src/mock/index.ts +5 -16
- package/src/specs/NativeAudioAPIModule.ts +1 -0
- package/src/specs/NativeAudioAPIModule.web.ts +2 -0
- package/src/types.ts +2 -1
- package/src/utils/flags.ts +12 -0
- package/src/utils/index.ts +24 -0
- package/src/utils/paths.ts +11 -0
- package/src/utils/remoteHttpSource.ts +87 -0
- package/src/web-core/AudioBufferSourceNode.web.ts +9 -1
- package/src/web-core/AudioContext.web.ts +4 -2
- package/src/web-core/AudioDecoder.web.ts +10 -7
- package/src/web-core/BaseAudioContext.web.ts +3 -1
- package/src/web-core/OfflineAudioContext.web.ts +4 -2
- package/src/web-core/custom/index.ts +1 -0
- package/src/web-core/custom/wasm-audio-bufffer-source-node-stretcher/AudioBufferSourceNodeStretcher.ts +72 -12
- package/src/web-core/custom/wasm-audio-bufffer-source-node-stretcher/LoadCustomWasm.ts +39 -0
- package/src/web-core/types.web.ts +4 -1
- package/src/web-core/utils/AudioBufferSourceNodeStandard.ts +12 -2
- package/lib/commonjs/utils/metadataPrefetching.js +0 -67
- package/lib/commonjs/utils/metadataPrefetching.js.map +0 -1
- package/lib/commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.d.js +0 -6
- package/lib/commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.d.js.map +0 -1
- package/lib/commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.js.map +0 -1
- package/lib/module/utils/metadataPrefetching.js +0 -61
- package/lib/module/utils/metadataPrefetching.js.map +0 -1
- package/lib/module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.d.js +0 -4
- package/lib/module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.d.js.map +0 -1
- package/lib/module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.js.map +0 -1
- package/lib/typescript/utils/metadataPrefetching.d.ts +0 -16
- package/lib/typescript/utils/metadataPrefetching.d.ts.map +0 -1
- package/src/utils/metadataPrefetching.ts +0 -96
- package/src/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.d.ts +0 -4
- /package/src/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/{SignalsmithStretch.js → SignalsmithStretch.mjs} +0 -0
package/android/build.gradle
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include <audioapi/android/AudioAPIModule.h>
|
|
2
2
|
#include <audioapi/android/JniEventPayloadParser.h>
|
|
3
|
+
#include <audioapi/android/system/NativeFileInfo.hpp>
|
|
3
4
|
#include <memory>
|
|
4
5
|
|
|
5
6
|
namespace audioapi {
|
|
@@ -53,6 +54,9 @@ void AudioAPIModule::registerNatives() {
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
void AudioAPIModule::injectJSIBindings() {
|
|
57
|
+
// cache app directory paths on the attached thread
|
|
58
|
+
NativeFileInfo::warmCache();
|
|
59
|
+
|
|
56
60
|
#if RN_AUDIO_API_ENABLE_WORKLETS
|
|
57
61
|
auto uiWorkletRuntime = weakWorkletsModuleProxy_.lock()->getUIWorkletRuntime();
|
|
58
62
|
#else
|
|
@@ -63,8 +63,8 @@ void AndroidFileWriterBackend::cleanupPreallocatedInputPool() {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
void AndroidFileWriterBackend::writeAudioData(void *data, int numFrames) {
|
|
66
|
-
if (offloader_ == nullptr || freeSlots_ == nullptr ||
|
|
67
|
-
inputBuffers_.empty()) {
|
|
66
|
+
if (!isFileOpen() || offloader_ == nullptr || freeSlots_ == nullptr ||
|
|
67
|
+
inputBufferBytesPerSlot_ == 0 || inputBuffers_.empty()) {
|
|
68
68
|
return;
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -28,7 +28,9 @@ OpenFileResult AndroidRotatingFileWriter::openFile(
|
|
|
28
28
|
streamSampleRate_ = streamSampleRate;
|
|
29
29
|
streamChannelCount_ = streamChannelCount;
|
|
30
30
|
streamMaxBufferSize_ = streamMaxBufferSizeInFrames;
|
|
31
|
-
|
|
31
|
+
if (!fileNameOverride.empty()) {
|
|
32
|
+
fileProperties_->fileNamePrefix = fileNameOverride + fileProperties_->fileNamePrefix;
|
|
33
|
+
}
|
|
32
34
|
if (currentWriter_ == nullptr) {
|
|
33
35
|
currentWriter_ = writerFactory_(fileProperties_);
|
|
34
36
|
}
|
|
@@ -108,7 +108,9 @@ CloseFileResult FFmpegAudioFileWriter::closeFile() {
|
|
|
108
108
|
return CloseFileResult::Err("File is not open");
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
isFileOpen_.store(false, std::memory_order_release);
|
|
112
|
+
|
|
113
|
+
// Drains the worker queue before flushing/finalizing the encoder below.
|
|
112
114
|
cleanupPreallocatedInputPool();
|
|
113
115
|
|
|
114
116
|
result = processFifo(true);
|
|
@@ -466,10 +468,12 @@ CloseFileResult FFmpegAudioFileWriter::finalizeOutput() {
|
|
|
466
468
|
avio_closep(&formatCtx_->pb);
|
|
467
469
|
}
|
|
468
470
|
|
|
469
|
-
double durationInSeconds =
|
|
471
|
+
double durationInSeconds = 0.0;
|
|
472
|
+
if (encoderCtx_ != nullptr && encoderCtx_->sample_rate > 0) {
|
|
473
|
+
durationInSeconds = static_cast<double>(nextPts_) / encoderCtx_->sample_rate;
|
|
474
|
+
}
|
|
470
475
|
|
|
471
476
|
filePath_ = "";
|
|
472
|
-
isFileOpen_.store(false, std::memory_order_release);
|
|
473
477
|
|
|
474
478
|
return CloseFileResult::Ok({fileSizeInMB, durationInSeconds});
|
|
475
479
|
}
|
package/android/src/main/cpp/audioapi/android/core/utils/miniaudioBackend/MiniAudioFileWriter.cpp
CHANGED
|
@@ -156,11 +156,11 @@ CloseFileResult MiniAudioFileWriter::closeFile() {
|
|
|
156
156
|
return CloseFileResult ::Err("File is not open");
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
// Joins the worker before the encoder teardown below.
|
|
160
|
-
cleanupPreallocatedInputPool();
|
|
161
|
-
|
|
162
159
|
isFileOpen_.store(false, std::memory_order_release);
|
|
163
160
|
|
|
161
|
+
// Drains the worker queue before the encoder teardown below.
|
|
162
|
+
cleanupPreallocatedInputPool();
|
|
163
|
+
|
|
164
164
|
if (encoder_ != nullptr) {
|
|
165
165
|
ma_encoder_uninit(encoder_.get());
|
|
166
166
|
encoder_.reset();
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#include <audioapi/android/system/NativeFileInfo.hpp>
|
|
2
|
+
|
|
3
|
+
#include <atomic>
|
|
4
|
+
#include <string>
|
|
5
|
+
|
|
6
|
+
namespace audioapi {
|
|
7
|
+
|
|
8
|
+
namespace {
|
|
9
|
+
|
|
10
|
+
std::string cachedFilesDir;
|
|
11
|
+
std::string cachedCacheDir;
|
|
12
|
+
std::atomic<bool> cacheReady{false};
|
|
13
|
+
|
|
14
|
+
std::string fetchFilesDirFromJava() {
|
|
15
|
+
static const auto method =
|
|
16
|
+
NativeFileInfo::javaClassStatic()->getStaticMethod<jni::JString()>("getFilesDir");
|
|
17
|
+
return method(NativeFileInfo::javaClassStatic())->toStdString();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
std::string fetchCacheDirFromJava() {
|
|
21
|
+
static const auto method =
|
|
22
|
+
NativeFileInfo::javaClassStatic()->getStaticMethod<jni::JString()>("getCacheDir");
|
|
23
|
+
return method(NativeFileInfo::javaClassStatic())->toStdString();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
} // namespace
|
|
27
|
+
|
|
28
|
+
void NativeFileInfo::warmCache() {
|
|
29
|
+
cachedFilesDir = fetchFilesDirFromJava();
|
|
30
|
+
cachedCacheDir = fetchCacheDirFromJava();
|
|
31
|
+
cacheReady.store(true, std::memory_order_release);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
std::string NativeFileInfo::getFilesDir() {
|
|
35
|
+
if (cacheReady.load(std::memory_order_acquire)) {
|
|
36
|
+
return cachedFilesDir;
|
|
37
|
+
}
|
|
38
|
+
return fetchFilesDirFromJava();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
std::string NativeFileInfo::getCacheDir() {
|
|
42
|
+
if (cacheReady.load(std::memory_order_acquire)) {
|
|
43
|
+
return cachedCacheDir;
|
|
44
|
+
}
|
|
45
|
+
return fetchCacheDirFromJava();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
} // namespace audioapi
|
|
@@ -7,19 +7,17 @@ namespace audioapi {
|
|
|
7
7
|
|
|
8
8
|
using namespace facebook;
|
|
9
9
|
|
|
10
|
+
/// @brief JNI bridge to Kotlin paths for recorder file output.
|
|
11
|
+
/// @note Call warmCache() from a JNI-attached thread
|
|
10
12
|
class NativeFileInfo : public jni::JavaClass<NativeFileInfo> {
|
|
11
13
|
public:
|
|
12
14
|
static auto constexpr kJavaDescriptor = "Lcom/swmansion/audioapi/system/NativeFileInfo;";
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return method(javaClassStatic())->toStdString();
|
|
17
|
-
}
|
|
16
|
+
/// @brief Fetches and caches directory paths via JNI. Must run before recording.
|
|
17
|
+
static void warmCache();
|
|
18
18
|
|
|
19
|
-
static std::string
|
|
20
|
-
|
|
21
|
-
return method(javaClassStatic())->toStdString();
|
|
22
|
-
}
|
|
19
|
+
static std::string getFilesDir();
|
|
20
|
+
static std::string getCacheDir();
|
|
23
21
|
};
|
|
24
22
|
|
|
25
23
|
} // namespace audioapi
|
|
@@ -109,6 +109,8 @@ class AudioAPIModule(
|
|
|
109
109
|
|
|
110
110
|
override fun getDevicePreferredSampleRate(): Double = MediaSessionManager.getDevicePreferredSampleRate()
|
|
111
111
|
|
|
112
|
+
override fun isFfmpegEnabled(): Boolean = !BuildConfig.RN_AUDIO_API_FFMPEG_DISABLED
|
|
113
|
+
|
|
112
114
|
override fun setAudioSessionActivity(
|
|
113
115
|
enabled: Boolean,
|
|
114
116
|
promise: Promise?,
|
|
@@ -43,6 +43,10 @@ public abstract class NativeAudioAPIModuleSpec extends ReactContextBaseJavaModul
|
|
|
43
43
|
@DoNotStrip
|
|
44
44
|
public abstract double getDevicePreferredSampleRate();
|
|
45
45
|
|
|
46
|
+
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
47
|
+
@DoNotStrip
|
|
48
|
+
public abstract boolean isFfmpegEnabled();
|
|
49
|
+
|
|
46
50
|
@ReactMethod
|
|
47
51
|
@DoNotStrip
|
|
48
52
|
public abstract void setAudioSessionActivity(boolean enabled, Promise promise);
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
#include <audioapi/HostObjects/utils/JsEnumParser.h>
|
|
24
24
|
#include <audioapi/HostObjects/utils/NodeOptionsParser.h>
|
|
25
25
|
#include <audioapi/core/BaseAudioContext.h>
|
|
26
|
-
#include <audioapi/core/utils/AudioDecoding.
|
|
26
|
+
#include <audioapi/core/utils/AudioDecoding.h>
|
|
27
27
|
|
|
28
28
|
#include <memory>
|
|
29
29
|
#include <vector>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#include <audioapi/HostObjects/sources/AudioBufferHostObject.h>
|
|
2
2
|
#include <audioapi/HostObjects/utils/AudioDecoderHostObject.h>
|
|
3
|
-
#include <audioapi/core/utils/AudioDecoding.
|
|
3
|
+
#include <audioapi/core/utils/AudioDecoding.h>
|
|
4
4
|
#include <audioapi/jsi/JsiPromise.h>
|
|
5
5
|
|
|
6
6
|
#include <jsi/jsi.h>
|
|
@@ -16,7 +16,6 @@ AudioDecoderHostObject::AudioDecoderHostObject(
|
|
|
16
16
|
addFunctions(
|
|
17
17
|
JSI_EXPORT_FUNCTION(AudioDecoderHostObject, decodeWithPCMInBase64),
|
|
18
18
|
JSI_EXPORT_FUNCTION(AudioDecoderHostObject, decodeWithFilePath),
|
|
19
|
-
JSI_EXPORT_FUNCTION(AudioDecoderHostObject, getDurationWithFilePath),
|
|
20
19
|
JSI_EXPORT_FUNCTION(AudioDecoderHostObject, decodeWithMemoryBlock));
|
|
21
20
|
}
|
|
22
21
|
|
|
@@ -77,28 +76,6 @@ JSI_HOST_FUNCTION_IMPL(AudioDecoderHostObject, decodeWithFilePath) {
|
|
|
77
76
|
return promise;
|
|
78
77
|
}
|
|
79
78
|
|
|
80
|
-
JSI_HOST_FUNCTION_IMPL(AudioDecoderHostObject, getDurationWithFilePath) {
|
|
81
|
-
auto sourcePath = args[0].getString(runtime).utf8(runtime);
|
|
82
|
-
|
|
83
|
-
auto promise = promiseVendor_->createAsyncPromise([sourcePath]() -> PromiseResolver {
|
|
84
|
-
auto result = audiodecoding::getDurationWithFilePath(sourcePath);
|
|
85
|
-
|
|
86
|
-
if (result.is_err()) {
|
|
87
|
-
return [result = std::move(result)](
|
|
88
|
-
jsi::Runtime &runtime) -> std::variant<jsi::Value, std::string> {
|
|
89
|
-
return result.unwrap_err();
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const auto duration = result.unwrap();
|
|
94
|
-
return [duration](jsi::Runtime &runtime) -> std::variant<jsi::Value, std::string> {
|
|
95
|
-
return jsi::Value(duration);
|
|
96
|
-
};
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
return promise;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
79
|
JSI_HOST_FUNCTION_IMPL(AudioDecoderHostObject, decodeWithPCMInBase64) {
|
|
103
80
|
auto b64 = args[0].getString(runtime).utf8(runtime);
|
|
104
81
|
auto inputSampleRate = static_cast<float>(args[1].getNumber());
|
|
@@ -16,7 +16,6 @@ class AudioDecoderHostObject : public JsiHostObject {
|
|
|
16
16
|
const std::shared_ptr<react::CallInvoker> &callInvoker);
|
|
17
17
|
JSI_HOST_FUNCTION_DECL(decodeWithMemoryBlock);
|
|
18
18
|
JSI_HOST_FUNCTION_DECL(decodeWithFilePath);
|
|
19
|
-
JSI_HOST_FUNCTION_DECL(getDurationWithFilePath);
|
|
20
19
|
JSI_HOST_FUNCTION_DECL(decodeWithPCMInBase64);
|
|
21
20
|
|
|
22
21
|
private:
|
|
@@ -1,40 +1,19 @@
|
|
|
1
1
|
#include <audioapi/HostObjects/utils/AudioFileUtilsHostObject.h>
|
|
2
|
+
#include <audioapi/HostObjects/utils/NodeOptionsParser.h>
|
|
3
|
+
#include <audioapi/core/utils/AudioDecoding.h>
|
|
2
4
|
#include <audioapi/core/utils/AudioFileConcatenator.h>
|
|
3
|
-
#if !RN_AUDIO_API_FFMPEG_DISABLED
|
|
4
|
-
#include <audioapi/libs/ffmpeg/FFmpegDecoding.h>
|
|
5
|
-
#endif // RN_AUDIO_API_FFMPEG_DISABLED
|
|
6
|
-
#include <audioapi/core/utils/AudioDecoding.hpp>
|
|
7
5
|
#include <audioapi/jsi/JsiPromise.h>
|
|
8
|
-
#include <audioapi/libs/miniaudio/MiniAudioDecoding.h>
|
|
9
6
|
|
|
10
7
|
#include <jsi/jsi.h>
|
|
11
8
|
#include <cstdint>
|
|
9
|
+
#include <map>
|
|
12
10
|
#include <memory>
|
|
13
|
-
#include <optional>
|
|
14
11
|
#include <string>
|
|
15
12
|
#include <utility>
|
|
16
13
|
#include <vector>
|
|
17
14
|
|
|
18
15
|
namespace audioapi {
|
|
19
16
|
|
|
20
|
-
namespace {
|
|
21
|
-
|
|
22
|
-
std::optional<double> probeDurationWithDecoder(const uint8_t *data, size_t size, int sampleRate) {
|
|
23
|
-
auto duration =
|
|
24
|
-
audiodecoding::probeDuration<miniaudio_decoder::MiniAudioDecoder>(data, size, sampleRate);
|
|
25
|
-
if (duration.has_value()) {
|
|
26
|
-
return duration;
|
|
27
|
-
}
|
|
28
|
-
#if !RN_AUDIO_API_FFMPEG_DISABLED
|
|
29
|
-
duration = audiodecoding::probeDuration<ffmpeg_decoder::FFmpegDecoder>(data, size, sampleRate);
|
|
30
|
-
return duration;
|
|
31
|
-
#else
|
|
32
|
-
return std::nullopt;
|
|
33
|
-
#endif // RN_AUDIO_API_FFMPEG_DISABLED
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
} // namespace
|
|
37
|
-
|
|
38
17
|
AudioFileUtilsHostObject::AudioFileUtilsHostObject(
|
|
39
18
|
jsi::Runtime *runtime,
|
|
40
19
|
const std::shared_ptr<react::CallInvoker> &callInvoker) {
|
|
@@ -85,38 +64,67 @@ JSI_HOST_FUNCTION_IMPL(AudioFileUtilsHostObject, concatAudioFiles) {
|
|
|
85
64
|
}
|
|
86
65
|
|
|
87
66
|
JSI_HOST_FUNCTION_IMPL(AudioFileUtilsHostObject, probeDuration) {
|
|
88
|
-
if (count < 1
|
|
89
|
-
throw jsi::JSError(runtime, "probeDuration expects an ArrayBuffer.");
|
|
67
|
+
if (count < 1) {
|
|
68
|
+
throw jsi::JSError(runtime, "probeDuration expects an ArrayBuffer or URL/path string.");
|
|
90
69
|
}
|
|
91
70
|
|
|
92
|
-
auto
|
|
93
|
-
|
|
94
|
-
|
|
71
|
+
const auto sampleRate =
|
|
72
|
+
count > 1 && args[1].isNumber() ? static_cast<int>(args[1].getNumber()) : 0;
|
|
73
|
+
|
|
74
|
+
if (args[0].isObject() && args[0].asObject(runtime).isArrayBuffer(runtime)) {
|
|
75
|
+
auto arrayBuffer = args[0].asObject(runtime).getArrayBuffer(runtime);
|
|
76
|
+
const auto *data = arrayBuffer.data(runtime);
|
|
77
|
+
const auto size = arrayBuffer.size(runtime);
|
|
78
|
+
|
|
79
|
+
auto promise = promiseVendor_->createAsyncPromise(
|
|
80
|
+
[bytes = std::vector<uint8_t>(data, data + size), sampleRate]() -> PromiseResolver {
|
|
81
|
+
auto result =
|
|
82
|
+
audiodecoding::probeDurationWithMemory(bytes.data(), bytes.size(), sampleRate);
|
|
83
|
+
if (result.is_err()) {
|
|
84
|
+
return [](jsi::Runtime &runtime) -> std::variant<jsi::Value, std::string> {
|
|
85
|
+
return jsi::Value::null();
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return [duration = static_cast<double>(result.unwrap())](
|
|
90
|
+
jsi::Runtime &runtime) -> std::variant<jsi::Value, std::string> {
|
|
91
|
+
return jsi::Value(duration);
|
|
92
|
+
};
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
return promise;
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const auto size = arrayBuffer.size(runtime);
|
|
98
|
+
if (args[0].isString()) {
|
|
99
|
+
const auto pathOrUrl = args[0].asString(runtime).utf8(runtime);
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
std::map<std::string, std::string> headers;
|
|
102
|
+
if (count > 2 && args[2].isObject()) {
|
|
103
|
+
headers = audioapi::option_parser::parseHttpHeaders(runtime, args[2].asObject(runtime));
|
|
104
|
+
}
|
|
103
105
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
auto promise = promiseVendor_->createAsyncPromise(
|
|
107
|
+
[pathOrUrl, sampleRate, headers = std::move(headers)]() -> PromiseResolver {
|
|
108
|
+
auto result = audiodecoding::isHttpUrl(pathOrUrl)
|
|
109
|
+
? audiodecoding::probeDurationWithUrl(pathOrUrl, sampleRate, headers)
|
|
110
|
+
: audiodecoding::probeDurationWithFilePath(pathOrUrl);
|
|
111
|
+
|
|
112
|
+
if (result.is_err()) {
|
|
113
|
+
return [](jsi::Runtime &runtime) -> std::variant<jsi::Value, std::string> {
|
|
114
|
+
return jsi::Value::null();
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return [duration = static_cast<double>(result.unwrap())](
|
|
119
|
+
jsi::Runtime &runtime) -> std::variant<jsi::Value, std::string> {
|
|
120
|
+
return jsi::Value(duration);
|
|
110
121
|
};
|
|
111
|
-
}
|
|
122
|
+
});
|
|
112
123
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return jsi::Value(duration);
|
|
116
|
-
};
|
|
117
|
-
});
|
|
124
|
+
return promise;
|
|
125
|
+
}
|
|
118
126
|
|
|
119
|
-
|
|
127
|
+
throw jsi::JSError(runtime, "probeDuration expects an ArrayBuffer or URL/path string.");
|
|
120
128
|
}
|
|
121
129
|
|
|
122
130
|
} // namespace audioapi
|
|
@@ -6,15 +6,46 @@
|
|
|
6
6
|
#include <cstddef>
|
|
7
7
|
#include <cstdio>
|
|
8
8
|
#include <limits>
|
|
9
|
+
#include <map>
|
|
9
10
|
#include <memory>
|
|
11
|
+
#include <string>
|
|
10
12
|
#include <vector>
|
|
11
13
|
|
|
12
14
|
#include <audioapi/HostObjects/effects/PeriodicWaveHostObject.h>
|
|
13
15
|
#include <audioapi/HostObjects/sources/AudioBufferHostObject.h>
|
|
14
|
-
#include <audioapi/core/utils/AudioDecoding.
|
|
16
|
+
#include <audioapi/core/utils/AudioDecoding.h>
|
|
15
17
|
#include <audioapi/types/NodeOptions.h>
|
|
16
18
|
|
|
17
19
|
namespace audioapi::option_parser {
|
|
20
|
+
|
|
21
|
+
inline std::map<std::string, std::string> parseHttpHeaders(
|
|
22
|
+
jsi::Runtime &runtime,
|
|
23
|
+
const jsi::Object &headersObject) {
|
|
24
|
+
std::map<std::string, std::string> headers;
|
|
25
|
+
const auto propertyNames = headersObject.getPropertyNames(runtime);
|
|
26
|
+
const auto count = propertyNames.size(runtime);
|
|
27
|
+
for (size_t i = 0; i < count; ++i) {
|
|
28
|
+
const auto keyValue = propertyNames.getValueAtIndex(runtime, i);
|
|
29
|
+
if (!keyValue.isString()) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const auto key = keyValue.asString(runtime).utf8(runtime);
|
|
33
|
+
const auto value = headersObject.getProperty(runtime, key.c_str());
|
|
34
|
+
if (value.isString()) {
|
|
35
|
+
headers.emplace(key, value.asString(runtime).utf8(runtime));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return headers;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
inline void mergeHttpHeaders(
|
|
42
|
+
std::map<std::string, std::string> &target,
|
|
43
|
+
const std::map<std::string, std::string> &incoming) {
|
|
44
|
+
for (const auto &[key, value] : incoming) {
|
|
45
|
+
target[key] = value;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
18
49
|
inline AudioNodeOptions parseAudioNodeOptions(
|
|
19
50
|
jsi::Runtime &runtime,
|
|
20
51
|
const jsi::Object &optionsObject) {
|
|
@@ -320,12 +351,29 @@ inline AudioFileSourceOptions parseAudioFileSourceOptions(
|
|
|
320
351
|
|
|
321
352
|
auto sourceValue = optionsObject.getProperty(runtime, "source");
|
|
322
353
|
if (sourceValue.isString()) {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
354
|
+
const auto path = sourceValue.asString(runtime).utf8(runtime);
|
|
355
|
+
if (audiodecoding::isHttpUrl(path)) {
|
|
356
|
+
options.sourceUrl = path;
|
|
357
|
+
options.requiresFFmpeg = true;
|
|
358
|
+
} else {
|
|
359
|
+
options.filePath = path;
|
|
360
|
+
options.requiresFFmpeg =
|
|
361
|
+
audiodecoding::pathHasExtension(path, {".mp4", ".m4a", ".aac", ".m3u8"});
|
|
362
|
+
}
|
|
326
363
|
} else if (sourceValue.isObject()) {
|
|
327
364
|
auto sourceObj = sourceValue.asObject(runtime);
|
|
328
|
-
if (sourceObj.
|
|
365
|
+
if (sourceObj.hasProperty(runtime, "uri")) {
|
|
366
|
+
const auto uriValue = sourceObj.getProperty(runtime, "uri");
|
|
367
|
+
if (uriValue.isString()) {
|
|
368
|
+
options.sourceUrl = uriValue.asString(runtime).utf8(runtime);
|
|
369
|
+
options.requiresFFmpeg = true;
|
|
370
|
+
}
|
|
371
|
+
const auto sourceHeadersValue = sourceObj.getProperty(runtime, "headers");
|
|
372
|
+
if (sourceHeadersValue.isObject()) {
|
|
373
|
+
mergeHttpHeaders(
|
|
374
|
+
options.httpHeaders, parseHttpHeaders(runtime, sourceHeadersValue.asObject(runtime)));
|
|
375
|
+
}
|
|
376
|
+
} else if (sourceObj.isArrayBuffer(runtime)) {
|
|
329
377
|
auto arrayBuffer = sourceObj.getArrayBuffer(runtime);
|
|
330
378
|
auto *data = arrayBuffer.data(runtime);
|
|
331
379
|
auto size = arrayBuffer.size(runtime);
|
|
@@ -336,11 +384,17 @@ inline AudioFileSourceOptions parseAudioFileSourceOptions(
|
|
|
336
384
|
}
|
|
337
385
|
}
|
|
338
386
|
|
|
387
|
+
const auto headersValue = optionsObject.getProperty(runtime, "headers");
|
|
388
|
+
if (headersValue.isObject()) {
|
|
389
|
+
mergeHttpHeaders(
|
|
390
|
+
options.httpHeaders, parseHttpHeaders(runtime, headersValue.asObject(runtime)));
|
|
391
|
+
}
|
|
392
|
+
|
|
339
393
|
#if RN_AUDIO_API_FFMPEG_DISABLED
|
|
340
394
|
if (options.requiresFFmpeg) {
|
|
341
395
|
throw jsi::JSError(
|
|
342
396
|
runtime,
|
|
343
|
-
"AudioFileSourceNode:
|
|
397
|
+
"AudioFileSourceNode: remote URLs and formats (.mp4, .m4a, .aac, .m3u8) require FFmpeg, "
|
|
344
398
|
"which is disabled in this build.");
|
|
345
399
|
}
|
|
346
400
|
#endif
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
#include <audioapi/core/sources/StreamerNode.h>
|
|
22
22
|
#endif // RN_AUDIO_API_FFMPEG_DISABLED
|
|
23
23
|
#include <audioapi/core/sources/WorkletSourceNode.h>
|
|
24
|
-
#include <audioapi/core/utils/AudioDecoding.
|
|
24
|
+
#include <audioapi/core/utils/AudioDecoding.h>
|
|
25
25
|
#include <audioapi/core/utils/AudioGraphManager.h>
|
|
26
26
|
#include <audioapi/core/utils/worklets/SafeIncludes.h>
|
|
27
27
|
#include <audioapi/events/AudioEventHandlerRegistry.h>
|
|
@@ -43,9 +43,12 @@ AudioFileSourceNode::AudioFileSourceNode(
|
|
|
43
43
|
|
|
44
44
|
const bool useFilePath = !options.filePath.empty();
|
|
45
45
|
const bool useData = !options.data.empty();
|
|
46
|
+
const bool useUrl = !options.sourceUrl.empty();
|
|
46
47
|
|
|
47
|
-
if (!useFilePath && !useData) {
|
|
48
|
-
assert(
|
|
48
|
+
if (!useFilePath && !useData && !useUrl) {
|
|
49
|
+
assert(
|
|
50
|
+
false &&
|
|
51
|
+
"AudioFileSourceNode requires a file path, remote URL, or memory data to initialize");
|
|
49
52
|
return;
|
|
50
53
|
}
|
|
51
54
|
|
|
@@ -103,6 +106,8 @@ bool AudioFileSourceNode::initDecoder(
|
|
|
103
106
|
SeekDecoderDaemonOptions daemonOptions{
|
|
104
107
|
.requiresFFmpeg = options.requiresFFmpeg,
|
|
105
108
|
.filePath = std::move(options.filePath),
|
|
109
|
+
.sourceUrl = std::move(options.sourceUrl),
|
|
110
|
+
.httpHeaders = std::move(options.httpHeaders),
|
|
106
111
|
.memoryData = std::move(options.data),
|
|
107
112
|
.contextSampleRate = context->getSampleRate(),
|
|
108
113
|
.loop = options.loop};
|