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.
Files changed (296) hide show
  1. package/README.md +40 -39
  2. package/RNAudioAPI.podspec +17 -12
  3. package/android/build.gradle +44 -4
  4. package/android/src/main/cpp/audioapi/CMakeLists.txt +65 -0
  5. package/android/src/main/cpp/audioapi/android/AudioAPIModule.cpp +29 -1
  6. package/android/src/main/cpp/audioapi/android/AudioAPIModule.h +14 -0
  7. package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +7 -1
  8. package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.h +6 -1
  9. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +1 -1
  10. package/android/src/main/cpp/audioapi/android/core/NativeAudioRecorder.hpp +36 -0
  11. package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +11 -1
  12. package/android/src/main/java/com/swmansion/audioapi/core/NativeAudioRecorder.kt +24 -0
  13. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +15 -2
  14. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +53 -18
  15. package/common/cpp/audioapi/HostObjects/AudioContextHostObject.cpp +57 -0
  16. package/common/cpp/audioapi/HostObjects/AudioContextHostObject.h +6 -46
  17. package/common/cpp/audioapi/HostObjects/AudioNodeHostObject.cpp +70 -6
  18. package/common/cpp/audioapi/HostObjects/AudioNodeHostObject.h +10 -66
  19. package/common/cpp/audioapi/HostObjects/AudioParamHostObject.cpp +105 -0
  20. package/common/cpp/audioapi/HostObjects/AudioParamHostObject.h +17 -91
  21. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +362 -6
  22. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +29 -241
  23. package/common/cpp/audioapi/HostObjects/OfflineAudioContextHostObject.cpp +70 -0
  24. package/common/cpp/audioapi/HostObjects/OfflineAudioContextHostObject.h +6 -50
  25. package/common/cpp/audioapi/HostObjects/WorkletNodeHostObject.h +18 -0
  26. package/common/cpp/audioapi/HostObjects/WorkletProcessingNodeHostObject.h +18 -0
  27. package/common/cpp/audioapi/HostObjects/analysis/AnalyserNodeHostObject.cpp +148 -0
  28. package/common/cpp/audioapi/HostObjects/analysis/AnalyserNodeHostObject.h +37 -0
  29. package/common/cpp/audioapi/HostObjects/effects/BiquadFilterNodeHostObject.cpp +92 -0
  30. package/common/cpp/audioapi/HostObjects/effects/BiquadFilterNodeHostObject.h +29 -0
  31. package/common/cpp/audioapi/HostObjects/effects/GainNodeHostObject.cpp +20 -0
  32. package/common/cpp/audioapi/HostObjects/effects/GainNodeHostObject.h +19 -0
  33. package/common/cpp/audioapi/HostObjects/effects/StereoPannerNodeHostObject.cpp +21 -0
  34. package/common/cpp/audioapi/HostObjects/effects/StereoPannerNodeHostObject.h +21 -0
  35. package/common/cpp/audioapi/HostObjects/events/AudioEventHandlerRegistryHostObject.cpp +41 -0
  36. package/common/cpp/audioapi/HostObjects/events/AudioEventHandlerRegistryHostObject.h +28 -0
  37. package/common/cpp/audioapi/HostObjects/inputs/AudioRecorderHostObject.cpp +69 -0
  38. package/common/cpp/audioapi/HostObjects/inputs/AudioRecorderHostObject.h +33 -0
  39. package/common/cpp/audioapi/HostObjects/sources/AudioBufferBaseSourceNodeHostObject.cpp +73 -0
  40. package/common/cpp/audioapi/HostObjects/sources/AudioBufferBaseSourceNodeHostObject.h +29 -0
  41. package/common/cpp/audioapi/HostObjects/sources/AudioBufferHostObject.cpp +94 -0
  42. package/common/cpp/audioapi/HostObjects/sources/AudioBufferHostObject.h +46 -0
  43. package/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.cpp +60 -0
  44. package/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.h +25 -0
  45. package/common/cpp/audioapi/HostObjects/sources/AudioBufferSourceNodeHostObject.cpp +152 -0
  46. package/common/cpp/audioapi/HostObjects/sources/AudioBufferSourceNodeHostObject.h +37 -0
  47. package/common/cpp/audioapi/HostObjects/sources/AudioScheduledSourceNodeHostObject.cpp +52 -0
  48. package/common/cpp/audioapi/HostObjects/sources/AudioScheduledSourceNodeHostObject.h +25 -0
  49. package/common/cpp/audioapi/HostObjects/sources/ConstantSourceNodeHostObject.cpp +19 -0
  50. package/common/cpp/audioapi/HostObjects/sources/ConstantSourceNodeHostObject.h +21 -0
  51. package/common/cpp/audioapi/HostObjects/sources/OscillatorNodeHostObject.cpp +55 -0
  52. package/common/cpp/audioapi/HostObjects/sources/OscillatorNodeHostObject.h +27 -0
  53. package/common/cpp/audioapi/HostObjects/{RecorderAdapterNodeHostObject.h → sources/RecorderAdapterNodeHostObject.h} +1 -2
  54. package/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.cpp +22 -0
  55. package/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.h +28 -0
  56. package/common/cpp/audioapi/HostObjects/sources/WorkletSourceNodeHostObject.h +18 -0
  57. package/common/cpp/audioapi/core/AudioContext.cpp +3 -2
  58. package/common/cpp/audioapi/core/AudioContext.h +2 -1
  59. package/common/cpp/audioapi/core/AudioNode.cpp +3 -3
  60. package/common/cpp/audioapi/core/AudioNode.h +2 -2
  61. package/common/cpp/audioapi/core/AudioParam.cpp +2 -2
  62. package/common/cpp/audioapi/core/AudioParam.h +1 -1
  63. package/common/cpp/audioapi/core/BaseAudioContext.cpp +47 -3
  64. package/common/cpp/audioapi/core/BaseAudioContext.h +13 -4
  65. package/common/cpp/audioapi/core/OfflineAudioContext.cpp +4 -3
  66. package/common/cpp/audioapi/core/OfflineAudioContext.h +2 -1
  67. package/common/cpp/audioapi/core/analysis/AnalyserNode.cpp +3 -1
  68. package/common/cpp/audioapi/core/analysis/AnalyserNode.h +1 -1
  69. package/common/cpp/audioapi/core/destinations/AudioDestinationNode.h +1 -1
  70. package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +3 -1
  71. package/common/cpp/audioapi/core/effects/BiquadFilterNode.h +1 -1
  72. package/common/cpp/audioapi/core/effects/GainNode.cpp +3 -1
  73. package/common/cpp/audioapi/core/effects/GainNode.h +1 -1
  74. package/common/cpp/audioapi/core/effects/PeriodicWave.cpp +1 -1
  75. package/common/cpp/audioapi/core/effects/StereoPannerNode.cpp +18 -13
  76. package/common/cpp/audioapi/core/effects/StereoPannerNode.h +1 -1
  77. package/common/cpp/audioapi/core/effects/WorkletNode.cpp +89 -0
  78. package/common/cpp/audioapi/core/effects/WorkletNode.h +65 -0
  79. package/common/cpp/audioapi/core/effects/WorkletProcessingNode.cpp +91 -0
  80. package/common/cpp/audioapi/core/effects/WorkletProcessingNode.h +52 -0
  81. package/common/cpp/audioapi/core/inputs/AudioRecorder.cpp +1 -1
  82. package/common/cpp/audioapi/core/inputs/AudioRecorder.h +2 -2
  83. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +47 -10
  84. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +18 -3
  85. package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +98 -14
  86. package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h +9 -3
  87. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +37 -44
  88. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +7 -9
  89. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +1 -6
  90. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +1 -1
  91. package/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp +53 -0
  92. package/common/cpp/audioapi/core/sources/ConstantSourceNode.h +26 -0
  93. package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +7 -2
  94. package/common/cpp/audioapi/core/sources/OscillatorNode.h +1 -1
  95. package/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp +3 -1
  96. package/common/cpp/audioapi/core/sources/RecorderAdapterNode.h +1 -1
  97. package/common/cpp/audioapi/core/sources/StreamerNode.cpp +9 -1
  98. package/common/cpp/audioapi/core/sources/StreamerNode.h +1 -9
  99. package/common/cpp/audioapi/core/sources/WorkletSourceNode.cpp +84 -0
  100. package/common/cpp/audioapi/core/sources/WorkletSourceNode.h +47 -0
  101. package/common/cpp/audioapi/core/{AudioParamEventQueue.cpp → utils/AudioParamEventQueue.cpp} +13 -7
  102. package/common/cpp/audioapi/core/{Constants.h → utils/Constants.h} +5 -0
  103. package/common/cpp/audioapi/core/utils/worklets/SafeIncludes.h +52 -0
  104. package/common/cpp/audioapi/core/utils/worklets/WorkletsRunner.cpp +9 -0
  105. package/common/cpp/audioapi/core/utils/worklets/WorkletsRunner.h +73 -0
  106. package/common/cpp/audioapi/dsp/Windows.cpp +1 -1
  107. package/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp +1 -1
  108. package/common/cpp/audioapi/events/AudioEventHandlerRegistry.h +2 -1
  109. package/common/cpp/audioapi/jsi/AudioArrayBuffer.h +14 -1
  110. package/common/cpp/audioapi/jsi/JsiHostObject.h +6 -12
  111. package/common/cpp/audioapi/jsi/JsiPromise.cpp +49 -0
  112. package/common/cpp/audioapi/jsi/JsiPromise.h +29 -1
  113. package/common/cpp/audioapi/utils/AudioBus.cpp +1 -1
  114. package/common/cpp/audioapi/utils/ThreadPool.hpp +104 -0
  115. package/common/cpp/test/AudioParamTest.cpp +204 -0
  116. package/common/cpp/test/CMakeLists.txt +12 -3
  117. package/common/cpp/test/GainTest.cpp +11 -10
  118. package/common/cpp/test/OscillatorTest.cpp +2 -1
  119. package/common/cpp/test/StereoPannerTest.cpp +129 -0
  120. package/ios/audioapi/ios/AudioAPIModule.mm +32 -5
  121. package/ios/audioapi/ios/core/IOSAudioPlayer.mm +1 -1
  122. package/ios/audioapi/ios/core/IOSAudioRecorder.mm +1 -1
  123. package/lib/commonjs/api.js +36 -2
  124. package/lib/commonjs/api.js.map +1 -1
  125. package/lib/commonjs/api.web.js +8 -0
  126. package/lib/commonjs/api.web.js.map +1 -1
  127. package/lib/commonjs/core/AudioBufferBaseSourceNode.js +7 -7
  128. package/lib/commonjs/core/AudioBufferBaseSourceNode.js.map +1 -1
  129. package/lib/commonjs/core/AudioBufferQueueSourceNode.js +1 -6
  130. package/lib/commonjs/core/AudioBufferQueueSourceNode.js.map +1 -1
  131. package/lib/commonjs/core/AudioBufferSourceNode.js +15 -0
  132. package/lib/commonjs/core/AudioBufferSourceNode.js.map +1 -1
  133. package/lib/commonjs/core/AudioContext.js +10 -1
  134. package/lib/commonjs/core/AudioContext.js.map +1 -1
  135. package/lib/commonjs/core/AudioScheduledSourceNode.js +4 -4
  136. package/lib/commonjs/core/AudioScheduledSourceNode.js.map +1 -1
  137. package/lib/commonjs/core/BaseAudioContext.js +66 -11
  138. package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
  139. package/lib/commonjs/core/ConstantSourceNode.js +17 -0
  140. package/lib/commonjs/core/ConstantSourceNode.js.map +1 -0
  141. package/lib/commonjs/core/OfflineAudioContext.js +11 -2
  142. package/lib/commonjs/core/OfflineAudioContext.js.map +1 -1
  143. package/lib/commonjs/core/OscillatorNode.js +6 -0
  144. package/lib/commonjs/core/OscillatorNode.js.map +1 -1
  145. package/lib/commonjs/core/WorkletNode.js +11 -0
  146. package/lib/commonjs/core/WorkletNode.js.map +1 -0
  147. package/lib/commonjs/core/WorkletProcessingNode.js +11 -0
  148. package/lib/commonjs/core/WorkletProcessingNode.js.map +1 -0
  149. package/lib/commonjs/core/WorkletSourceNode.js +11 -0
  150. package/lib/commonjs/core/WorkletSourceNode.js.map +1 -0
  151. package/lib/commonjs/hooks/{useSytemVolume.js → useSystemVolume.js} +1 -1
  152. package/lib/commonjs/hooks/useSystemVolume.js.map +1 -0
  153. package/lib/commonjs/utils/index.js +9 -0
  154. package/lib/commonjs/utils/index.js.map +1 -1
  155. package/lib/commonjs/web-core/AudioContext.js +4 -0
  156. package/lib/commonjs/web-core/AudioContext.js.map +1 -1
  157. package/lib/commonjs/web-core/AudioScheduledSourceNode.js +1 -1
  158. package/lib/commonjs/web-core/AudioScheduledSourceNode.js.map +1 -1
  159. package/lib/commonjs/web-core/ConstantSourceNode.js +17 -0
  160. package/lib/commonjs/web-core/ConstantSourceNode.js.map +1 -0
  161. package/lib/commonjs/web-core/OfflineAudioContext.js +4 -0
  162. package/lib/commonjs/web-core/OfflineAudioContext.js.map +1 -1
  163. package/lib/module/api.js +6 -2
  164. package/lib/module/api.js.map +1 -1
  165. package/lib/module/api.web.js +1 -0
  166. package/lib/module/api.web.js.map +1 -1
  167. package/lib/module/core/AudioBufferBaseSourceNode.js +7 -7
  168. package/lib/module/core/AudioBufferBaseSourceNode.js.map +1 -1
  169. package/lib/module/core/AudioBufferQueueSourceNode.js +1 -6
  170. package/lib/module/core/AudioBufferQueueSourceNode.js.map +1 -1
  171. package/lib/module/core/AudioBufferSourceNode.js +15 -0
  172. package/lib/module/core/AudioBufferSourceNode.js.map +1 -1
  173. package/lib/module/core/AudioContext.js +10 -1
  174. package/lib/module/core/AudioContext.js.map +1 -1
  175. package/lib/module/core/AudioScheduledSourceNode.js +4 -4
  176. package/lib/module/core/AudioScheduledSourceNode.js.map +1 -1
  177. package/lib/module/core/BaseAudioContext.js +66 -11
  178. package/lib/module/core/BaseAudioContext.js.map +1 -1
  179. package/lib/module/core/ConstantSourceNode.js +11 -0
  180. package/lib/module/core/ConstantSourceNode.js.map +1 -0
  181. package/lib/module/core/OfflineAudioContext.js +11 -2
  182. package/lib/module/core/OfflineAudioContext.js.map +1 -1
  183. package/lib/module/core/OscillatorNode.js +6 -0
  184. package/lib/module/core/OscillatorNode.js.map +1 -1
  185. package/lib/module/core/WorkletNode.js +5 -0
  186. package/lib/module/core/WorkletNode.js.map +1 -0
  187. package/lib/module/core/WorkletProcessingNode.js +5 -0
  188. package/lib/module/core/WorkletProcessingNode.js.map +1 -0
  189. package/lib/module/core/WorkletSourceNode.js +5 -0
  190. package/lib/module/core/WorkletSourceNode.js.map +1 -0
  191. package/lib/module/hooks/{useSytemVolume.js → useSystemVolume.js} +1 -1
  192. package/lib/module/hooks/useSystemVolume.js.map +1 -0
  193. package/lib/module/utils/index.js +8 -0
  194. package/lib/module/utils/index.js.map +1 -1
  195. package/lib/module/web-core/AudioContext.js +4 -0
  196. package/lib/module/web-core/AudioContext.js.map +1 -1
  197. package/lib/module/web-core/AudioScheduledSourceNode.js +1 -1
  198. package/lib/module/web-core/AudioScheduledSourceNode.js.map +1 -1
  199. package/lib/module/web-core/ConstantSourceNode.js +11 -0
  200. package/lib/module/web-core/ConstantSourceNode.js.map +1 -0
  201. package/lib/module/web-core/OfflineAudioContext.js +4 -0
  202. package/lib/module/web-core/OfflineAudioContext.js.map +1 -1
  203. package/lib/typescript/api.d.ts +8 -4
  204. package/lib/typescript/api.d.ts.map +1 -1
  205. package/lib/typescript/api.web.d.ts +1 -0
  206. package/lib/typescript/api.web.d.ts.map +1 -1
  207. package/lib/typescript/core/AudioBufferBaseSourceNode.d.ts +2 -2
  208. package/lib/typescript/core/AudioBufferBaseSourceNode.d.ts.map +1 -1
  209. package/lib/typescript/core/AudioBufferQueueSourceNode.d.ts +1 -1
  210. package/lib/typescript/core/AudioBufferQueueSourceNode.d.ts.map +1 -1
  211. package/lib/typescript/core/AudioBufferSourceNode.d.ts +4 -0
  212. package/lib/typescript/core/AudioBufferSourceNode.d.ts.map +1 -1
  213. package/lib/typescript/core/AudioContext.d.ts +1 -0
  214. package/lib/typescript/core/AudioContext.d.ts.map +1 -1
  215. package/lib/typescript/core/AudioScheduledSourceNode.d.ts +1 -1
  216. package/lib/typescript/core/BaseAudioContext.d.ts +19 -11
  217. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  218. package/lib/typescript/core/ConstantSourceNode.d.ts +9 -0
  219. package/lib/typescript/core/ConstantSourceNode.d.ts.map +1 -0
  220. package/lib/typescript/core/OfflineAudioContext.d.ts +1 -0
  221. package/lib/typescript/core/OfflineAudioContext.d.ts.map +1 -1
  222. package/lib/typescript/core/OscillatorNode.d.ts +3 -0
  223. package/lib/typescript/core/OscillatorNode.d.ts.map +1 -1
  224. package/lib/typescript/core/WorkletNode.d.ts +4 -0
  225. package/lib/typescript/core/WorkletNode.d.ts.map +1 -0
  226. package/lib/typescript/core/WorkletProcessingNode.d.ts +4 -0
  227. package/lib/typescript/core/WorkletProcessingNode.d.ts.map +1 -0
  228. package/lib/typescript/core/WorkletSourceNode.d.ts +4 -0
  229. package/lib/typescript/core/WorkletSourceNode.d.ts.map +1 -0
  230. package/lib/typescript/events/types.d.ts +2 -0
  231. package/lib/typescript/events/types.d.ts.map +1 -1
  232. package/lib/typescript/hooks/{useSytemVolume.d.ts → useSystemVolume.d.ts} +1 -1
  233. package/lib/typescript/hooks/useSystemVolume.d.ts.map +1 -0
  234. package/lib/typescript/interfaces.d.ts +21 -3
  235. package/lib/typescript/interfaces.d.ts.map +1 -1
  236. package/lib/typescript/types.d.ts +2 -1
  237. package/lib/typescript/types.d.ts.map +1 -1
  238. package/lib/typescript/utils/index.d.ts +8 -0
  239. package/lib/typescript/utils/index.d.ts.map +1 -1
  240. package/lib/typescript/web-core/AudioBufferSourceNode.d.ts +1 -1
  241. package/lib/typescript/web-core/AudioContext.d.ts +4 -2
  242. package/lib/typescript/web-core/AudioContext.d.ts.map +1 -1
  243. package/lib/typescript/web-core/AudioScheduledSourceNode.d.ts +1 -1
  244. package/lib/typescript/web-core/BaseAudioContext.d.ts +2 -0
  245. package/lib/typescript/web-core/BaseAudioContext.d.ts.map +1 -1
  246. package/lib/typescript/web-core/ConstantSourceNode.d.ts +8 -0
  247. package/lib/typescript/web-core/ConstantSourceNode.d.ts.map +1 -0
  248. package/lib/typescript/web-core/OfflineAudioContext.d.ts +4 -2
  249. package/lib/typescript/web-core/OfflineAudioContext.d.ts.map +1 -1
  250. package/package.json +3 -2
  251. package/src/api.ts +12 -3
  252. package/src/api.web.ts +1 -0
  253. package/src/core/AudioBufferBaseSourceNode.ts +9 -9
  254. package/src/core/AudioBufferQueueSourceNode.ts +1 -9
  255. package/src/core/AudioBufferSourceNode.ts +28 -0
  256. package/src/core/AudioContext.ts +12 -1
  257. package/src/core/AudioScheduledSourceNode.ts +5 -5
  258. package/src/core/BaseAudioContext.ts +149 -13
  259. package/src/core/ConstantSourceNode.ts +13 -0
  260. package/src/core/OfflineAudioContext.ts +18 -2
  261. package/src/core/OscillatorNode.ts +11 -0
  262. package/src/core/WorkletNode.ts +3 -0
  263. package/src/core/WorkletProcessingNode.ts +3 -0
  264. package/src/core/WorkletSourceNode.ts +3 -0
  265. package/src/events/types.ts +2 -0
  266. package/src/interfaces.ts +59 -5
  267. package/src/types.ts +3 -1
  268. package/src/utils/index.ts +21 -0
  269. package/src/web-core/AudioBufferSourceNode.tsx +1 -1
  270. package/src/web-core/AudioContext.tsx +7 -2
  271. package/src/web-core/AudioScheduledSourceNode.tsx +1 -1
  272. package/src/web-core/BaseAudioContext.tsx +2 -0
  273. package/src/web-core/ConstantSourceNode.tsx +12 -0
  274. package/src/web-core/OfflineAudioContext.tsx +7 -2
  275. package/common/cpp/audioapi/HostObjects/AnalyserNodeHostObject.h +0 -149
  276. package/common/cpp/audioapi/HostObjects/AudioBufferBaseSourceNodeHostObject.h +0 -76
  277. package/common/cpp/audioapi/HostObjects/AudioBufferHostObject.h +0 -120
  278. package/common/cpp/audioapi/HostObjects/AudioBufferQueueSourceNodeHostObject.h +0 -67
  279. package/common/cpp/audioapi/HostObjects/AudioBufferSourceNodeHostObject.h +0 -142
  280. package/common/cpp/audioapi/HostObjects/AudioRecorderHostObject.h +0 -86
  281. package/common/cpp/audioapi/HostObjects/AudioScheduledSourceNodeHostObject.h +0 -56
  282. package/common/cpp/audioapi/HostObjects/BiquadFilterNodeHostObject.h +0 -89
  283. package/common/cpp/audioapi/HostObjects/GainNodeHostObject.h +0 -27
  284. package/common/cpp/audioapi/HostObjects/OscillatorNodeHostObject.h +0 -65
  285. package/common/cpp/audioapi/HostObjects/StereoPannerNodeHostObject.h +0 -29
  286. package/common/cpp/audioapi/HostObjects/StreamerNodeHostObject.h +0 -30
  287. package/common/cpp/audioapi/events/AudioEventHandlerRegistryHostObject.h +0 -48
  288. package/ios/audioapi/ios/events/IOSAudioEventHandlerRegistry.h +0 -7
  289. package/ios/audioapi/ios/events/IOSAudioEventHandlerRegistry.mm +0 -12
  290. package/lib/commonjs/hooks/useSytemVolume.js.map +0 -1
  291. package/lib/module/hooks/useSytemVolume.js.map +0 -1
  292. package/lib/typescript/hooks/useSytemVolume.d.ts.map +0 -1
  293. /package/common/cpp/audioapi/HostObjects/{AudioDestinationNodeHostObject.h → destinations/AudioDestinationNodeHostObject.h} +0 -0
  294. /package/common/cpp/audioapi/HostObjects/{PeriodicWaveHostObject.h → effects/PeriodicWaveHostObject.h} +0 -0
  295. /package/common/cpp/audioapi/core/{AudioParamEventQueue.h → utils/AudioParamEventQueue.h} +0 -0
  296. /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
@@ -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 &front = eventQueue_.peekBack();
35
- if (front.getEndTime() < cancelTime) {
34
+ auto &back = eventQueue_.peekBack();
35
+ if (back.getEndTime() < cancelTime) {
36
36
  break;
37
37
  }
38
- if (front.getStartTime() >= cancelTime ||
39
- front.getType() == ParamChangeEventType::SET_VALUE_CURVE) {
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 &front = eventQueue_.peekBack();
50
- if (front.getEndTime() < cancelTime || front.getStartTime() <= cancelTime) {
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,9 @@
1
+ #include <audioapi/core/utils/worklets/WorkletsRunner.h>
2
+
3
+ namespace audioapi {
4
+
5
+ WorkletsRunner::WorkletsRunner(
6
+ std::weak_ptr<worklets::WorkletRuntime> weakUiRuntime) noexcept
7
+ : weakUiRuntime_(std::move(weakUiRuntime)) {}
8
+
9
+ }; // namespace audioapi
@@ -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
@@ -1,4 +1,4 @@
1
- #include <audioapi/core/Constants.h>
1
+ #include <audioapi/core/utils/Constants.h>
2
2
  #include <audioapi/dsp/Windows.h>
3
3
 
4
4
  namespace audioapi::dsp {
@@ -1,4 +1,4 @@
1
- #include <audioapi/HostObjects/AudioBufferHostObject.h>
1
+ #include <audioapi/HostObjects/sources/AudioBufferHostObject.h>
2
2
  #include <audioapi/events/AudioEventHandlerRegistry.h>
3
3
 
4
4
  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, 5> AUDIO_API_EVENT_NAMES = {
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 = default;
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 JSI_HOST_FUNCTION(NAME) \
14
- jsi::Value NAME( \
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 JSI_PROPERTY_GETTER(name) jsi::Value name(jsi::Runtime &runtime)
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 JSI_PROPERTY_SETTER(name) \
36
- void name(jsi::Runtime &runtime, const jsi::Value &value)
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): runtime_(runtime), 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
@@ -1,4 +1,4 @@
1
- #include <audioapi/core/Constants.h>
1
+ #include <audioapi/core/utils/Constants.h>
2
2
  #include <audioapi/dsp/VectorMath.h>
3
3
  #include <audioapi/utils/AudioArray.h>
4
4
  #include <audioapi/utils/AudioBus.h>
@@ -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