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.
Files changed (219) hide show
  1. package/android/build.gradle +1 -0
  2. package/android/src/main/cpp/audioapi/android/AudioAPIModule.cpp +4 -0
  3. package/android/src/main/cpp/audioapi/android/core/utils/AndroidFileWriterBackend.cpp +2 -2
  4. package/android/src/main/cpp/audioapi/android/core/utils/AndroidRotatingFileWriter.cpp +3 -1
  5. package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/FFmpegFileWriter.cpp +7 -3
  6. package/android/src/main/cpp/audioapi/android/core/utils/miniaudioBackend/MiniAudioFileWriter.cpp +3 -3
  7. package/android/src/main/cpp/audioapi/android/system/NativeFileInfo.cpp +48 -0
  8. package/android/src/main/cpp/audioapi/android/system/NativeFileInfo.hpp +6 -8
  9. package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +2 -0
  10. package/android/src/oldarch/NativeAudioAPIModuleSpec.java +4 -0
  11. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +1 -1
  12. package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.cpp +1 -24
  13. package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.h +0 -1
  14. package/common/cpp/audioapi/HostObjects/utils/AudioFileUtilsHostObject.cpp +55 -47
  15. package/common/cpp/audioapi/HostObjects/utils/NodeOptionsParser.h +60 -6
  16. package/common/cpp/audioapi/core/BaseAudioContext.cpp +1 -1
  17. package/common/cpp/audioapi/core/sources/AudioFileSourceNode.cpp +7 -2
  18. package/common/cpp/audioapi/core/utils/AudioDecoding.cpp +69 -25
  19. package/common/cpp/audioapi/core/utils/{AudioDecoding.hpp → AudioDecoding.h} +18 -13
  20. package/common/cpp/audioapi/core/utils/decoding/SeekDecoderDaemon.cpp +4 -4
  21. package/common/cpp/audioapi/core/utils/decoding/SeekDecoderDaemon.h +3 -0
  22. package/common/cpp/audioapi/libs/decoding/IncrementalAudioDecoder.h +11 -0
  23. package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp +72 -48
  24. package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.h +10 -1
  25. package/common/cpp/audioapi/libs/miniaudio/MiniAudioDecoding.cpp +7 -0
  26. package/common/cpp/audioapi/libs/miniaudio/MiniAudioDecoding.h +5 -0
  27. package/common/cpp/audioapi/types/NodeOptions.h +3 -0
  28. package/common/cpp/audioapi/utils/TaskOffloader.hpp +43 -11
  29. package/ios/audioapi/ios/AudioAPIModule.mm +9 -0
  30. package/ios/audioapi/ios/core/utils/IOSFileWriter.mm +6 -3
  31. package/ios/audioapi/ios/core/utils/IOSRotatingFileWriter.mm +3 -1
  32. package/lib/commonjs/Audio/Audio.js +2 -0
  33. package/lib/commonjs/Audio/Audio.js.map +1 -1
  34. package/lib/commonjs/Audio/useAudioSourceLoader.js +15 -11
  35. package/lib/commonjs/Audio/useAudioSourceLoader.js.map +1 -1
  36. package/lib/commonjs/Audio/utils.js +4 -1
  37. package/lib/commonjs/Audio/utils.js.map +1 -1
  38. package/lib/commonjs/api.js +10 -2
  39. package/lib/commonjs/api.js.map +1 -1
  40. package/lib/commonjs/api.web.js +6 -0
  41. package/lib/commonjs/api.web.js.map +1 -1
  42. package/lib/commonjs/core/AudioDecoder.js +1 -32
  43. package/lib/commonjs/core/AudioDecoder.js.map +1 -1
  44. package/lib/commonjs/core/AudioFileUtils.js +32 -11
  45. package/lib/commonjs/core/AudioFileUtils.js.map +1 -1
  46. package/lib/commonjs/mock/index.js +5 -5
  47. package/lib/commonjs/mock/index.js.map +1 -1
  48. package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -1
  49. package/lib/commonjs/specs/NativeAudioAPIModule.web.js +1 -0
  50. package/lib/commonjs/specs/NativeAudioAPIModule.web.js.map +1 -1
  51. package/lib/commonjs/types.js.map +1 -1
  52. package/lib/commonjs/utils/flags.js +18 -0
  53. package/lib/commonjs/utils/flags.js.map +1 -0
  54. package/lib/commonjs/utils/index.js +24 -0
  55. package/lib/commonjs/utils/index.js.map +1 -1
  56. package/lib/commonjs/utils/paths.js +9 -0
  57. package/lib/commonjs/utils/paths.js.map +1 -1
  58. package/lib/commonjs/utils/remoteHttpSource.js +80 -0
  59. package/lib/commonjs/utils/remoteHttpSource.js.map +1 -0
  60. package/lib/commonjs/web-core/AudioBufferSourceNode.web.js +7 -1
  61. package/lib/commonjs/web-core/AudioBufferSourceNode.web.js.map +1 -1
  62. package/lib/commonjs/web-core/AudioContext.web.js +2 -4
  63. package/lib/commonjs/web-core/AudioContext.web.js.map +1 -1
  64. package/lib/commonjs/web-core/AudioDecoder.web.js +6 -2
  65. package/lib/commonjs/web-core/AudioDecoder.web.js.map +1 -1
  66. package/lib/commonjs/web-core/OfflineAudioContext.web.js +2 -4
  67. package/lib/commonjs/web-core/OfflineAudioContext.web.js.map +1 -1
  68. package/lib/commonjs/web-core/custom/index.js +7 -0
  69. package/lib/commonjs/web-core/custom/index.js.map +1 -1
  70. package/lib/commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/AudioBufferSourceNodeStretcher.js +58 -6
  71. package/lib/commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/AudioBufferSourceNodeStretcher.js.map +1 -1
  72. package/lib/commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/LoadCustomWasm.js +37 -0
  73. package/lib/commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/LoadCustomWasm.js.map +1 -0
  74. 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
  75. package/lib/commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.mjs.map +1 -0
  76. package/lib/commonjs/web-core/utils/AudioBufferSourceNodeStandard.js +8 -2
  77. package/lib/commonjs/web-core/utils/AudioBufferSourceNodeStandard.js.map +1 -1
  78. package/lib/module/Audio/Audio.js +2 -0
  79. package/lib/module/Audio/Audio.js.map +1 -1
  80. package/lib/module/Audio/useAudioSourceLoader.js +16 -12
  81. package/lib/module/Audio/useAudioSourceLoader.js.map +1 -1
  82. package/lib/module/Audio/utils.js +4 -1
  83. package/lib/module/Audio/utils.js.map +1 -1
  84. package/lib/module/api.js +3 -2
  85. package/lib/module/api.js.map +1 -1
  86. package/lib/module/api.web.js +3 -0
  87. package/lib/module/api.web.js.map +1 -1
  88. package/lib/module/core/AudioDecoder.js +2 -32
  89. package/lib/module/core/AudioDecoder.js.map +1 -1
  90. package/lib/module/core/AudioFileUtils.js +31 -11
  91. package/lib/module/core/AudioFileUtils.js.map +1 -1
  92. package/lib/module/mock/index.js +4 -5
  93. package/lib/module/mock/index.js.map +1 -1
  94. package/lib/module/specs/NativeAudioAPIModule.js.map +1 -1
  95. package/lib/module/specs/NativeAudioAPIModule.web.js +1 -0
  96. package/lib/module/specs/NativeAudioAPIModule.web.js.map +1 -1
  97. package/lib/module/types.js.map +1 -1
  98. package/lib/module/utils/flags.js +15 -0
  99. package/lib/module/utils/flags.js.map +1 -0
  100. package/lib/module/utils/index.js +17 -0
  101. package/lib/module/utils/index.js.map +1 -1
  102. package/lib/module/utils/paths.js +8 -0
  103. package/lib/module/utils/paths.js.map +1 -1
  104. package/lib/module/utils/remoteHttpSource.js +75 -0
  105. package/lib/module/utils/remoteHttpSource.js.map +1 -0
  106. package/lib/module/web-core/AudioBufferSourceNode.web.js +7 -1
  107. package/lib/module/web-core/AudioBufferSourceNode.web.js.map +1 -1
  108. package/lib/module/web-core/AudioContext.web.js +2 -4
  109. package/lib/module/web-core/AudioContext.web.js.map +1 -1
  110. package/lib/module/web-core/AudioDecoder.web.js +6 -2
  111. package/lib/module/web-core/AudioDecoder.web.js.map +1 -1
  112. package/lib/module/web-core/OfflineAudioContext.web.js +2 -4
  113. package/lib/module/web-core/OfflineAudioContext.web.js.map +1 -1
  114. package/lib/module/web-core/custom/index.js +1 -0
  115. package/lib/module/web-core/custom/index.js.map +1 -1
  116. package/lib/module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/AudioBufferSourceNodeStretcher.js +57 -6
  117. package/lib/module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/AudioBufferSourceNodeStretcher.js.map +1 -1
  118. package/lib/module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/LoadCustomWasm.js +33 -0
  119. package/lib/module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/LoadCustomWasm.js.map +1 -0
  120. 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
  121. package/lib/module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.mjs.map +1 -0
  122. package/lib/module/web-core/utils/AudioBufferSourceNodeStandard.js +8 -2
  123. package/lib/module/web-core/utils/AudioBufferSourceNodeStandard.js.map +1 -1
  124. package/lib/typescript/Audio/Audio.d.ts.map +1 -1
  125. package/lib/typescript/Audio/types.d.ts +5 -0
  126. package/lib/typescript/Audio/types.d.ts.map +1 -1
  127. package/lib/typescript/Audio/useAudioSourceLoader.d.ts +2 -1
  128. package/lib/typescript/Audio/useAudioSourceLoader.d.ts.map +1 -1
  129. package/lib/typescript/Audio/utils.d.ts.map +1 -1
  130. package/lib/typescript/api.d.ts +3 -2
  131. package/lib/typescript/api.d.ts.map +1 -1
  132. package/lib/typescript/api.web.d.ts +1 -0
  133. package/lib/typescript/api.web.d.ts.map +1 -1
  134. package/lib/typescript/core/AudioDecoder.d.ts +1 -2
  135. package/lib/typescript/core/AudioDecoder.d.ts.map +1 -1
  136. package/lib/typescript/core/AudioFileUtils.d.ts +3 -3
  137. package/lib/typescript/core/AudioFileUtils.d.ts.map +1 -1
  138. package/lib/typescript/jsi-interfaces.d.ts +1 -2
  139. package/lib/typescript/jsi-interfaces.d.ts.map +1 -1
  140. package/lib/typescript/mock/index.d.ts +3 -1
  141. package/lib/typescript/mock/index.d.ts.map +1 -1
  142. package/lib/typescript/specs/NativeAudioAPIModule.d.ts +1 -0
  143. package/lib/typescript/specs/NativeAudioAPIModule.d.ts.map +1 -1
  144. package/lib/typescript/specs/NativeAudioAPIModule.web.d.ts +1 -0
  145. package/lib/typescript/specs/NativeAudioAPIModule.web.d.ts.map +1 -1
  146. package/lib/typescript/types.d.ts +2 -1
  147. package/lib/typescript/types.d.ts.map +1 -1
  148. package/lib/typescript/utils/flags.d.ts +9 -0
  149. package/lib/typescript/utils/flags.d.ts.map +1 -0
  150. package/lib/typescript/utils/index.d.ts +2 -0
  151. package/lib/typescript/utils/index.d.ts.map +1 -1
  152. package/lib/typescript/utils/paths.d.ts +1 -0
  153. package/lib/typescript/utils/paths.d.ts.map +1 -1
  154. package/lib/typescript/utils/remoteHttpSource.d.ts +7 -0
  155. package/lib/typescript/utils/remoteHttpSource.d.ts.map +1 -0
  156. package/lib/typescript/web-core/AudioBufferSourceNode.web.d.ts +2 -0
  157. package/lib/typescript/web-core/AudioBufferSourceNode.web.d.ts.map +1 -1
  158. package/lib/typescript/web-core/AudioContext.web.d.ts +3 -1
  159. package/lib/typescript/web-core/AudioContext.web.d.ts.map +1 -1
  160. package/lib/typescript/web-core/AudioDecoder.web.d.ts +1 -1
  161. package/lib/typescript/web-core/AudioDecoder.web.d.ts.map +1 -1
  162. package/lib/typescript/web-core/BaseAudioContext.web.d.ts +3 -1
  163. package/lib/typescript/web-core/BaseAudioContext.web.d.ts.map +1 -1
  164. package/lib/typescript/web-core/OfflineAudioContext.web.d.ts +3 -1
  165. package/lib/typescript/web-core/OfflineAudioContext.web.d.ts.map +1 -1
  166. package/lib/typescript/web-core/custom/index.d.ts +1 -0
  167. package/lib/typescript/web-core/custom/index.d.ts.map +1 -1
  168. package/lib/typescript/web-core/custom/wasm-audio-bufffer-source-node-stretcher/AudioBufferSourceNodeStretcher.d.ts +5 -1
  169. package/lib/typescript/web-core/custom/wasm-audio-bufffer-source-node-stretcher/AudioBufferSourceNodeStretcher.d.ts.map +1 -1
  170. package/lib/typescript/web-core/custom/wasm-audio-bufffer-source-node-stretcher/LoadCustomWasm.d.ts +5 -0
  171. package/lib/typescript/web-core/custom/wasm-audio-bufffer-source-node-stretcher/LoadCustomWasm.d.ts.map +1 -0
  172. package/lib/typescript/web-core/types.web.d.ts +3 -1
  173. package/lib/typescript/web-core/types.web.d.ts.map +1 -1
  174. package/lib/typescript/web-core/utils/AudioBufferSourceNodeStandard.d.ts +2 -0
  175. package/lib/typescript/web-core/utils/AudioBufferSourceNodeStandard.d.ts.map +1 -1
  176. package/package.json +1 -1
  177. package/scripts/setup-rn-audio-api-web.js +4 -4
  178. package/src/Audio/Audio.tsx +2 -0
  179. package/src/Audio/types.ts +5 -0
  180. package/src/Audio/useAudioSourceLoader.ts +25 -15
  181. package/src/Audio/utils.ts +4 -0
  182. package/src/api.ts +3 -6
  183. package/src/api.web.ts +4 -0
  184. package/src/core/AudioDecoder.ts +3 -52
  185. package/src/core/AudioFileUtils.ts +66 -16
  186. package/src/jsi-interfaces.ts +3 -3
  187. package/src/mock/index.ts +5 -16
  188. package/src/specs/NativeAudioAPIModule.ts +1 -0
  189. package/src/specs/NativeAudioAPIModule.web.ts +2 -0
  190. package/src/types.ts +2 -1
  191. package/src/utils/flags.ts +12 -0
  192. package/src/utils/index.ts +24 -0
  193. package/src/utils/paths.ts +11 -0
  194. package/src/utils/remoteHttpSource.ts +87 -0
  195. package/src/web-core/AudioBufferSourceNode.web.ts +9 -1
  196. package/src/web-core/AudioContext.web.ts +4 -2
  197. package/src/web-core/AudioDecoder.web.ts +10 -7
  198. package/src/web-core/BaseAudioContext.web.ts +3 -1
  199. package/src/web-core/OfflineAudioContext.web.ts +4 -2
  200. package/src/web-core/custom/index.ts +1 -0
  201. package/src/web-core/custom/wasm-audio-bufffer-source-node-stretcher/AudioBufferSourceNodeStretcher.ts +72 -12
  202. package/src/web-core/custom/wasm-audio-bufffer-source-node-stretcher/LoadCustomWasm.ts +39 -0
  203. package/src/web-core/types.web.ts +4 -1
  204. package/src/web-core/utils/AudioBufferSourceNodeStandard.ts +12 -2
  205. package/lib/commonjs/utils/metadataPrefetching.js +0 -67
  206. package/lib/commonjs/utils/metadataPrefetching.js.map +0 -1
  207. package/lib/commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.d.js +0 -6
  208. package/lib/commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.d.js.map +0 -1
  209. package/lib/commonjs/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.js.map +0 -1
  210. package/lib/module/utils/metadataPrefetching.js +0 -61
  211. package/lib/module/utils/metadataPrefetching.js.map +0 -1
  212. package/lib/module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.d.js +0 -4
  213. package/lib/module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.d.js.map +0 -1
  214. package/lib/module/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.js.map +0 -1
  215. package/lib/typescript/utils/metadataPrefetching.d.ts +0 -16
  216. package/lib/typescript/utils/metadataPrefetching.d.ts.map +0 -1
  217. package/src/utils/metadataPrefetching.ts +0 -96
  218. package/src/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/SignalsmithStretch.d.ts +0 -4
  219. /package/src/web-core/custom/wasm-audio-bufffer-source-node-stretcher/signalsmithStretch/{SignalsmithStretch.js → SignalsmithStretch.mjs} +0 -0
@@ -216,6 +216,7 @@ android {
216
216
  "**/librrc_root.so",
217
217
  "**/libjscexecutor.so",
218
218
  "**/libv8executor.so",
219
+ "**/libworklets.so",
219
220
  "**/libreanimated.so"
220
221
  ]
221
222
  }
@@ -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 || inputBufferBytesPerSlot_ == 0 ||
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
- fileProperties_->fileNamePrefix = !fileNameOverride.empty() ? fileNameOverride : "recording";
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
- // Joins the worker before draining/finalizing the encoder below.
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 = getCurrentDuration();
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
  }
@@ -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
- static std::string getFilesDir() {
15
- static const auto method = javaClassStatic()->getStaticMethod<jni::JString()>("getFilesDir");
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 getCacheDir() {
20
- static const auto method = javaClassStatic()->getStaticMethod<jni::JString()>("getCacheDir");
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.hpp>
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.hpp>
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 || !args[0].isObject()) {
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 arrayBufferObject = args[0].asObject(runtime);
93
- if (!arrayBufferObject.isArrayBuffer(runtime)) {
94
- throw jsi::JSError(runtime, "probeDuration expects an ArrayBuffer.");
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
- auto arrayBuffer = arrayBufferObject.getArrayBuffer(runtime);
98
- const auto *data = arrayBuffer.data(runtime);
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
- const auto sampleRate =
102
- count > 1 && args[1].isNumber() ? static_cast<int>(args[1].getNumber()) : 0;
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
- auto promise = promiseVendor_->createAsyncPromise(
105
- [bytes = std::vector<uint8_t>(data, data + size), sampleRate]() -> PromiseResolver {
106
- auto duration = probeDurationWithDecoder(bytes.data(), bytes.size(), sampleRate);
107
- if (!duration.has_value()) {
108
- return [](jsi::Runtime &runtime) -> std::variant<jsi::Value, std::string> {
109
- return jsi::Value::null();
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
- return [duration = duration.value()](
114
- jsi::Runtime &runtime) -> std::variant<jsi::Value, std::string> {
115
- return jsi::Value(duration);
116
- };
117
- });
124
+ return promise;
125
+ }
118
126
 
119
- return promise;
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.hpp>
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
- options.filePath = sourceValue.asString(runtime).utf8(runtime);
324
- options.requiresFFmpeg =
325
- audiodecoding::pathHasExtension(options.filePath, {".mp4", ".m4a", ".aac", ".m3u8"});
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.isArrayBuffer(runtime)) {
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: source format (.mp4, .m4a, .aac, .m3u8) requires FFmpeg, "
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.hpp>
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(false && "AudioFileSourceNode requires either a file path or memory data to initialize");
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};