react-native-audio-api 0.11.0-alpha.1 → 0.11.0-alpha.2

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 (522) hide show
  1. package/README.md +13 -11
  2. package/RNAudioAPI.podspec +25 -18
  3. package/android/build.gradle +41 -5
  4. package/android/src/main/cpp/audioapi/CMakeLists.txt +6 -3
  5. package/android/src/main/cpp/audioapi/android/AudioAPIModule.cpp +10 -16
  6. package/android/src/main/cpp/audioapi/android/OnLoad.cpp +1 -2
  7. package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +219 -84
  8. package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.h +24 -23
  9. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +13 -20
  10. package/android/src/main/cpp/audioapi/android/core/utils/AndroidFileWriterBackend.h +14 -18
  11. package/android/src/main/cpp/audioapi/android/core/utils/AndroidRecorderCallback.cpp +72 -89
  12. package/android/src/main/cpp/audioapi/android/core/utils/AndroidRecorderCallback.h +12 -23
  13. package/android/src/main/cpp/audioapi/android/core/utils/AudioDecoder.cpp +47 -47
  14. package/android/src/main/cpp/audioapi/android/core/utils/FileOptions.cpp +83 -0
  15. package/android/src/main/cpp/audioapi/android/core/utils/FileOptions.h +22 -0
  16. package/android/src/main/cpp/audioapi/android/core/utils/MiniaudioImplementation.cpp +5 -0
  17. package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/FFmpegFileWriter.cpp +379 -298
  18. package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/FFmpegFileWriter.h +48 -91
  19. package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/ptrs.hpp +48 -0
  20. package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/utils.cpp +110 -0
  21. package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/utils.h +34 -0
  22. package/android/src/main/cpp/audioapi/android/core/utils/miniaudioBackend/MiniAudioFileWriter.cpp +132 -104
  23. package/android/src/main/cpp/audioapi/android/core/utils/miniaudioBackend/MiniAudioFileWriter.h +8 -16
  24. package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +28 -1
  25. package/android/src/main/java/com/swmansion/audioapi/system/LockScreenManager.kt +28 -6
  26. package/android/src/main/java/com/swmansion/audioapi/system/MediaNotificationManager.kt +11 -0
  27. package/android/src/main/jniLibs/arm64-v8a/libavcodec.so +0 -0
  28. package/android/src/main/jniLibs/arm64-v8a/libavformat.so +0 -0
  29. package/android/src/main/jniLibs/arm64-v8a/libavutil.so +0 -0
  30. package/android/src/main/jniLibs/arm64-v8a/libswresample.so +0 -0
  31. package/android/src/main/jniLibs/armeabi-v7a/libavcodec.so +0 -0
  32. package/android/src/main/jniLibs/armeabi-v7a/libavformat.so +0 -0
  33. package/android/src/main/jniLibs/armeabi-v7a/libavutil.so +0 -0
  34. package/android/src/main/jniLibs/armeabi-v7a/libswresample.so +0 -0
  35. package/android/src/main/jniLibs/x86/libavcodec.so +0 -0
  36. package/android/src/main/jniLibs/x86/libavformat.so +0 -0
  37. package/android/src/main/jniLibs/x86/libavutil.so +0 -0
  38. package/android/src/main/jniLibs/x86/libswresample.so +0 -0
  39. package/android/src/main/jniLibs/x86_64/libavcodec.so +0 -0
  40. package/android/src/main/jniLibs/x86_64/libavformat.so +0 -0
  41. package/android/src/main/jniLibs/x86_64/libavutil.so +0 -0
  42. package/android/src/main/jniLibs/x86_64/libswresample.so +0 -0
  43. package/android/src/oldarch/NativeAudioAPIModuleSpec.java +4 -0
  44. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +45 -70
  45. package/common/cpp/audioapi/HostObjects/AudioContextHostObject.cpp +20 -22
  46. package/common/cpp/audioapi/HostObjects/AudioNodeHostObject.cpp +3 -4
  47. package/common/cpp/audioapi/HostObjects/AudioParamHostObject.cpp +6 -8
  48. package/common/cpp/audioapi/HostObjects/AudioParamHostObject.h +2 -2
  49. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +102 -63
  50. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +4 -1
  51. package/common/cpp/audioapi/HostObjects/OfflineAudioContextHostObject.cpp +25 -31
  52. package/common/cpp/audioapi/HostObjects/OfflineAudioContextHostObject.h +3 -3
  53. package/common/cpp/audioapi/HostObjects/WorkletNodeHostObject.h +1 -2
  54. package/common/cpp/audioapi/HostObjects/WorkletProcessingNodeHostObject.h +1 -2
  55. package/common/cpp/audioapi/HostObjects/analysis/AnalyserNodeHostObject.cpp +10 -18
  56. package/common/cpp/audioapi/HostObjects/destinations/AudioDestinationNodeHostObject.h +2 -3
  57. package/common/cpp/audioapi/HostObjects/effects/BiquadFilterNodeHostObject.cpp +18 -30
  58. package/common/cpp/audioapi/HostObjects/effects/BiquadFilterNodeHostObject.h +1 -2
  59. package/common/cpp/audioapi/HostObjects/effects/ConvolverNodeHostObject.cpp +50 -0
  60. package/common/cpp/audioapi/HostObjects/effects/ConvolverNodeHostObject.h +20 -0
  61. package/common/cpp/audioapi/HostObjects/effects/DelayNodeHostObject.cpp +27 -0
  62. package/common/cpp/audioapi/HostObjects/effects/DelayNodeHostObject.h +21 -0
  63. package/common/cpp/audioapi/HostObjects/effects/GainNodeHostObject.cpp +2 -2
  64. package/common/cpp/audioapi/HostObjects/effects/IIRFilterNodeHostObject.cpp +33 -0
  65. package/common/cpp/audioapi/HostObjects/effects/IIRFilterNodeHostObject.h +20 -0
  66. package/common/cpp/audioapi/HostObjects/effects/PeriodicWaveHostObject.h +1 -2
  67. package/common/cpp/audioapi/HostObjects/effects/StereoPannerNodeHostObject.cpp +2 -2
  68. package/common/cpp/audioapi/HostObjects/effects/StereoPannerNodeHostObject.h +1 -2
  69. package/common/cpp/audioapi/HostObjects/events/AudioEventHandlerRegistryHostObject.cpp +6 -12
  70. package/common/cpp/audioapi/HostObjects/events/AudioEventHandlerRegistryHostObject.h +7 -7
  71. package/common/cpp/audioapi/HostObjects/inputs/AudioRecorderHostObject.cpp +98 -50
  72. package/common/cpp/audioapi/HostObjects/inputs/AudioRecorderHostObject.h +5 -2
  73. package/common/cpp/audioapi/HostObjects/sources/AudioBufferBaseSourceNodeHostObject.cpp +27 -22
  74. package/common/cpp/audioapi/HostObjects/sources/AudioBufferBaseSourceNodeHostObject.h +12 -10
  75. package/common/cpp/audioapi/HostObjects/sources/AudioBufferHostObject.cpp +17 -22
  76. package/common/cpp/audioapi/HostObjects/sources/AudioBufferHostObject.h +5 -7
  77. package/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.cpp +25 -11
  78. package/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.h +8 -8
  79. package/common/cpp/audioapi/HostObjects/sources/AudioBufferSourceNodeHostObject.cpp +19 -30
  80. package/common/cpp/audioapi/HostObjects/sources/AudioBufferSourceNodeHostObject.h +2 -4
  81. package/common/cpp/audioapi/HostObjects/sources/AudioScheduledSourceNodeHostObject.cpp +7 -11
  82. package/common/cpp/audioapi/HostObjects/sources/ConstantSourceNodeHostObject.cpp +2 -2
  83. package/common/cpp/audioapi/HostObjects/sources/ConstantSourceNodeHostObject.h +1 -2
  84. package/common/cpp/audioapi/HostObjects/sources/OscillatorNodeHostObject.cpp +6 -8
  85. package/common/cpp/audioapi/HostObjects/sources/OscillatorNodeHostObject.h +1 -2
  86. package/common/cpp/audioapi/HostObjects/sources/RecorderAdapterNodeHostObject.h +4 -5
  87. package/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.cpp +6 -2
  88. package/common/cpp/audioapi/HostObjects/sources/StreamerNodeHostObject.h +5 -6
  89. package/common/cpp/audioapi/HostObjects/sources/WorkletSourceNodeHostObject.h +1 -2
  90. package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.cpp +39 -60
  91. package/common/cpp/audioapi/HostObjects/utils/AudioStretcherHostObject.cpp +15 -30
  92. package/common/cpp/audioapi/core/AudioContext.cpp +23 -28
  93. package/common/cpp/audioapi/core/AudioContext.h +6 -3
  94. package/common/cpp/audioapi/core/AudioNode.cpp +17 -19
  95. package/common/cpp/audioapi/core/AudioNode.h +19 -8
  96. package/common/cpp/audioapi/core/AudioParam.cpp +68 -100
  97. package/common/cpp/audioapi/core/AudioParam.h +20 -12
  98. package/common/cpp/audioapi/core/BaseAudioContext.cpp +52 -34
  99. package/common/cpp/audioapi/core/BaseAudioContext.h +26 -14
  100. package/common/cpp/audioapi/core/OfflineAudioContext.cpp +12 -17
  101. package/common/cpp/audioapi/core/OfflineAudioContext.h +10 -5
  102. package/common/cpp/audioapi/core/analysis/AnalyserNode.cpp +13 -21
  103. package/common/cpp/audioapi/core/analysis/AnalyserNode.h +8 -6
  104. package/common/cpp/audioapi/core/destinations/AudioDestinationNode.cpp +1 -0
  105. package/common/cpp/audioapi/core/destinations/AudioDestinationNode.h +5 -3
  106. package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +84 -66
  107. package/common/cpp/audioapi/core/effects/BiquadFilterNode.h +39 -10
  108. package/common/cpp/audioapi/core/effects/ConvolverNode.cpp +201 -0
  109. package/common/cpp/audioapi/core/effects/ConvolverNode.h +64 -0
  110. package/common/cpp/audioapi/core/effects/DelayNode.cpp +101 -0
  111. package/common/cpp/audioapi/core/effects/DelayNode.h +39 -0
  112. package/common/cpp/audioapi/core/effects/GainNode.cpp +1 -0
  113. package/common/cpp/audioapi/core/effects/GainNode.h +3 -1
  114. package/common/cpp/audioapi/core/effects/IIRFilterNode.cpp +166 -0
  115. package/common/cpp/audioapi/core/effects/IIRFilterNode.h +74 -0
  116. package/common/cpp/audioapi/core/effects/PeriodicWave.cpp +22 -35
  117. package/common/cpp/audioapi/core/effects/PeriodicWave.h +4 -9
  118. package/common/cpp/audioapi/core/effects/StereoPannerNode.cpp +4 -5
  119. package/common/cpp/audioapi/core/effects/StereoPannerNode.h +4 -2
  120. package/common/cpp/audioapi/core/effects/WorkletNode.cpp +11 -13
  121. package/common/cpp/audioapi/core/effects/WorkletNode.h +15 -12
  122. package/common/cpp/audioapi/core/effects/WorkletProcessingNode.cpp +4 -4
  123. package/common/cpp/audioapi/core/effects/WorkletProcessingNode.h +15 -14
  124. package/common/cpp/audioapi/core/inputs/AudioRecorder.cpp +58 -36
  125. package/common/cpp/audioapi/core/inputs/AudioRecorder.h +41 -44
  126. package/common/cpp/audioapi/core/sources/AudioBuffer.cpp +4 -6
  127. package/common/cpp/audioapi/core/sources/AudioBuffer.h +4 -7
  128. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +48 -57
  129. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +37 -34
  130. package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +55 -17
  131. package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h +35 -28
  132. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +41 -49
  133. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +8 -6
  134. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +29 -24
  135. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +6 -6
  136. package/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp +3 -4
  137. package/common/cpp/audioapi/core/sources/ConstantSourceNode.h +3 -1
  138. package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +12 -23
  139. package/common/cpp/audioapi/core/sources/OscillatorNode.h +6 -4
  140. package/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp +43 -16
  141. package/common/cpp/audioapi/core/sources/RecorderAdapterNode.h +22 -17
  142. package/common/cpp/audioapi/core/sources/StreamerNode.cpp +104 -87
  143. package/common/cpp/audioapi/core/sources/StreamerNode.h +69 -33
  144. package/common/cpp/audioapi/core/sources/WorkletSourceNode.cpp +5 -7
  145. package/common/cpp/audioapi/core/sources/WorkletSourceNode.h +15 -13
  146. package/common/cpp/audioapi/core/types/AudioFormat.h +1 -11
  147. package/common/cpp/audioapi/core/utils/AudioDecoder.h +15 -6
  148. package/common/cpp/audioapi/core/utils/AudioFileWriter.cpp +41 -0
  149. package/common/cpp/audioapi/core/utils/AudioFileWriter.h +43 -0
  150. package/common/cpp/audioapi/core/utils/AudioNodeDestructor.cpp +5 -6
  151. package/common/cpp/audioapi/core/utils/AudioNodeDestructor.h +7 -10
  152. package/common/cpp/audioapi/core/utils/AudioNodeManager.cpp +17 -19
  153. package/common/cpp/audioapi/core/utils/AudioNodeManager.h +8 -11
  154. package/common/cpp/audioapi/core/utils/AudioParamEventQueue.cpp +3 -3
  155. package/common/cpp/audioapi/core/utils/AudioParamEventQueue.h +5 -5
  156. package/common/cpp/audioapi/core/utils/AudioRecorderCallback.cpp +101 -0
  157. package/common/cpp/audioapi/core/utils/AudioRecorderCallback.h +51 -0
  158. package/common/cpp/audioapi/core/utils/AudioStretcher.cpp +6 -6
  159. package/common/cpp/audioapi/core/utils/Constants.h +7 -3
  160. package/common/cpp/audioapi/core/utils/ParamChangeEvent.cpp +1 -0
  161. package/common/cpp/audioapi/core/utils/ParamChangeEvent.h +9 -9
  162. package/common/cpp/audioapi/core/utils/worklets/SafeIncludes.h +33 -34
  163. package/common/cpp/audioapi/core/utils/worklets/WorkletsRunner.cpp +17 -19
  164. package/common/cpp/audioapi/core/utils/worklets/WorkletsRunner.h +23 -19
  165. package/common/cpp/audioapi/dsp/AudioUtils.cpp +4 -10
  166. package/common/cpp/audioapi/dsp/AudioUtils.h +1 -1
  167. package/common/cpp/audioapi/dsp/Convolver.cpp +201 -0
  168. package/common/cpp/audioapi/dsp/Convolver.h +47 -0
  169. package/common/cpp/audioapi/dsp/FFT.cpp +1 -27
  170. package/common/cpp/audioapi/dsp/FFT.h +19 -3
  171. package/common/cpp/audioapi/dsp/VectorMath.cpp +24 -58
  172. package/common/cpp/audioapi/dsp/VectorMath.h +35 -8
  173. package/common/cpp/audioapi/dsp/Windows.cpp +4 -9
  174. package/common/cpp/audioapi/dsp/Windows.h +24 -23
  175. package/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp +12 -17
  176. package/common/cpp/audioapi/events/AudioEventHandlerRegistry.h +45 -40
  177. package/common/cpp/audioapi/events/IAudioEventHandlerRegistry.h +15 -7
  178. package/common/cpp/audioapi/external/ffmpeg_include/libavcodec/avcodec.h +4 -4
  179. package/common/cpp/audioapi/external/ffmpeg_include/libavcodec/codec.h +1 -1
  180. package/common/cpp/audioapi/external/ffmpeg_include/libavcodec/codec_desc.h +1 -1
  181. package/common/cpp/audioapi/external/ffmpeg_include/libavcodec/codec_id.h +3 -1
  182. package/common/cpp/audioapi/external/ffmpeg_include/libavcodec/codec_par.h +2 -2
  183. package/common/cpp/audioapi/external/ffmpeg_include/libavcodec/defs.h +3 -0
  184. package/common/cpp/audioapi/external/ffmpeg_include/libavcodec/packet.h +1 -1
  185. package/common/cpp/audioapi/external/ffmpeg_include/libavcodec/smpte_436m.h +254 -0
  186. package/common/cpp/audioapi/external/ffmpeg_include/libavcodec/version.h +1 -1
  187. package/common/cpp/audioapi/external/ffmpeg_include/libavformat/avformat.h +6 -6
  188. package/common/cpp/audioapi/external/ffmpeg_include/libavformat/version.h +2 -2
  189. package/common/cpp/audioapi/external/ffmpeg_include/libavformat/version_major.h +2 -0
  190. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/avassert.h +5 -2
  191. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/avutil.h +2 -2
  192. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/channel_layout.h +2 -2
  193. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/csp.h +1 -1
  194. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/dict.h +1 -1
  195. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/ffversion.h +1 -1
  196. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/film_grain_params.h +1 -1
  197. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/frame.h +1 -1
  198. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/hdr_dynamic_vivid_metadata.h +3 -3
  199. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/hwcontext.h +1 -1
  200. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/hwcontext_opencl.h +1 -1
  201. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/hwcontext_qsv.h +0 -1
  202. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/hwcontext_vulkan.h +1 -1
  203. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/iamf.h +2 -2
  204. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/lfg.h +2 -2
  205. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/log.h +2 -2
  206. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/mathematics.h +1 -1
  207. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/opt.h +4 -4
  208. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/rational.h +1 -1
  209. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/rc4.h +1 -1
  210. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/refstruct.h +1 -1
  211. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/spherical.h +6 -0
  212. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/tdrdi.h +1 -1
  213. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/tx.h +1 -1
  214. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/version.h +3 -3
  215. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/video_hint.h +1 -1
  216. package/common/cpp/audioapi/external/ffmpeg_include/libswresample/swresample.h +1 -1
  217. package/common/cpp/audioapi/external/ffmpeg_include/libswresample/version.h +1 -1
  218. package/common/cpp/audioapi/external/{libavcodec.xcframework → ffmpeg_ios/libavcodec.xcframework}/ios-arm64/libavcodec.framework/libavcodec +0 -0
  219. package/common/cpp/audioapi/external/{libavcodec.xcframework → ffmpeg_ios/libavcodec.xcframework}/ios-arm64_x86_64-simulator/libavcodec.framework/libavcodec +0 -0
  220. package/common/cpp/audioapi/external/{libavformat.xcframework → ffmpeg_ios/libavformat.xcframework}/ios-arm64/libavformat.framework/libavformat +0 -0
  221. package/common/cpp/audioapi/external/{libavformat.xcframework → ffmpeg_ios/libavformat.xcframework}/ios-arm64_x86_64-simulator/libavformat.framework/libavformat +0 -0
  222. package/common/cpp/audioapi/external/{libavutil.xcframework → ffmpeg_ios/libavutil.xcframework}/ios-arm64/libavutil.framework/libavutil +0 -0
  223. package/common/cpp/audioapi/external/{libavutil.xcframework → ffmpeg_ios/libavutil.xcframework}/ios-arm64_x86_64-simulator/libavutil.framework/libavutil +0 -0
  224. package/common/cpp/audioapi/external/{libswresample.xcframework → ffmpeg_ios/libswresample.xcframework}/ios-arm64/libswresample.framework/libswresample +0 -0
  225. package/common/cpp/audioapi/external/{libswresample.xcframework → ffmpeg_ios/libswresample.xcframework}/ios-arm64_x86_64-simulator/libswresample.framework/libswresample +0 -0
  226. package/common/cpp/audioapi/jsi/AudioArrayBuffer.h +4 -5
  227. package/common/cpp/audioapi/jsi/JsiHostObject.cpp +11 -13
  228. package/common/cpp/audioapi/jsi/JsiHostObject.h +26 -33
  229. package/common/cpp/audioapi/jsi/JsiPromise.cpp +34 -67
  230. package/common/cpp/audioapi/jsi/JsiPromise.h +65 -26
  231. package/common/cpp/audioapi/jsi/RuntimeLifecycleMonitor.cpp +7 -10
  232. package/common/cpp/audioapi/jsi/RuntimeLifecycleMonitor.h +1 -3
  233. package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp +4 -3
  234. package/common/cpp/audioapi/libs/ffmpeg/relinking.md +24 -0
  235. package/common/cpp/audioapi/utils/AlignedAllocator.hpp +50 -0
  236. package/common/cpp/audioapi/utils/AudioArray.cpp +3 -8
  237. package/common/cpp/audioapi/utils/AudioArray.h +3 -11
  238. package/common/cpp/audioapi/utils/AudioBus.cpp +79 -149
  239. package/common/cpp/audioapi/utils/AudioBus.h +17 -14
  240. package/common/cpp/audioapi/utils/AudioFileProperties.cpp +92 -0
  241. package/common/cpp/audioapi/utils/AudioFileProperties.h +76 -0
  242. package/common/cpp/audioapi/utils/CircularAudioArray.cpp +6 -18
  243. package/common/cpp/audioapi/utils/CircularOverflowableAudioArray.cpp +6 -10
  244. package/common/cpp/audioapi/utils/CircularOverflowableAudioArray.h +2 -2
  245. package/common/cpp/audioapi/utils/Result.hpp +286 -0
  246. package/common/cpp/audioapi/utils/ThreadPool.hpp +59 -1
  247. package/common/cpp/audioapi/utils/UnitConversion.h +9 -0
  248. package/common/cpp/test/CMakeLists.txt +20 -14
  249. package/common/cpp/test/src/AudioParamTest.cpp +4 -3
  250. package/common/cpp/test/src/AudioScheduledSourceTest.cpp +113 -0
  251. package/common/cpp/test/src/ConstantSourceTest.cpp +5 -7
  252. package/common/cpp/test/src/DelayTest.cpp +108 -0
  253. package/common/cpp/test/src/GainTest.cpp +4 -5
  254. package/common/cpp/test/src/IIRFilterTest.cpp +153 -0
  255. package/common/cpp/test/src/MockAudioEventHandlerRegistry.h +19 -11
  256. package/common/cpp/test/src/OscillatorTest.cpp +2 -1
  257. package/common/cpp/test/src/StereoPannerTest.cpp +6 -9
  258. package/common/cpp/test/src/biquad/BiquadFilterChromium.cpp +372 -0
  259. package/common/cpp/test/src/biquad/BiquadFilterChromium.h +65 -0
  260. package/common/cpp/test/src/biquad/BiquadFilterTest.cpp +272 -0
  261. package/common/cpp/test/src/biquad/BiquadFilterTest.h +47 -0
  262. package/ios/audioapi/ios/AudioAPIModule.h +2 -1
  263. package/ios/audioapi/ios/AudioAPIModule.mm +44 -20
  264. package/ios/audioapi/ios/core/IOSAudioPlayer.h +2 -2
  265. package/ios/audioapi/ios/core/IOSAudioPlayer.mm +7 -6
  266. package/ios/audioapi/ios/core/IOSAudioRecorder.h +26 -18
  267. package/ios/audioapi/ios/core/IOSAudioRecorder.mm +193 -53
  268. package/ios/audioapi/ios/core/NativeAudioPlayer.m +16 -13
  269. package/ios/audioapi/ios/core/NativeAudioRecorder.h +4 -0
  270. package/ios/audioapi/ios/core/NativeAudioRecorder.m +42 -7
  271. package/ios/audioapi/ios/core/utils/AudioDecoder.mm +21 -4
  272. package/ios/audioapi/ios/core/utils/FileOptions.h +31 -0
  273. package/ios/audioapi/ios/core/utils/FileOptions.mm +177 -0
  274. package/ios/audioapi/ios/core/{IOSAudioFileWriter.h → utils/IOSFileWriter.h} +16 -14
  275. package/ios/audioapi/ios/core/utils/IOSFileWriter.mm +224 -0
  276. package/ios/audioapi/ios/core/{IOSRecorderCallback.h → utils/IOSRecorderCallback.h} +7 -17
  277. package/ios/audioapi/ios/core/utils/IOSRecorderCallback.mm +172 -0
  278. package/ios/audioapi/ios/system/AudioEngine.h +19 -16
  279. package/ios/audioapi/ios/system/AudioEngine.mm +101 -134
  280. package/ios/audioapi/ios/system/AudioSessionManager.h +25 -11
  281. package/ios/audioapi/ios/system/AudioSessionManager.mm +273 -202
  282. package/ios/audioapi/ios/system/LockScreenManager.mm +39 -23
  283. package/ios/audioapi/ios/system/NotificationManager.mm +37 -52
  284. package/lib/commonjs/AudioAPIModule/AudioAPIModule.js +90 -0
  285. package/lib/commonjs/AudioAPIModule/AudioAPIModule.js.map +1 -0
  286. package/lib/commonjs/AudioAPIModule/globals.d.js +6 -0
  287. package/lib/commonjs/AudioAPIModule/globals.d.js.map +1 -0
  288. package/lib/commonjs/AudioAPIModule/index.js +14 -0
  289. package/lib/commonjs/AudioAPIModule/index.js.map +1 -0
  290. package/lib/commonjs/api.js +18 -12
  291. package/lib/commonjs/api.js.map +1 -1
  292. package/lib/commonjs/api.web.js +8 -0
  293. package/lib/commonjs/api.web.js.map +1 -1
  294. package/lib/commonjs/core/AudioBufferBaseSourceNode.js +3 -0
  295. package/lib/commonjs/core/AudioBufferBaseSourceNode.js.map +1 -1
  296. package/lib/commonjs/core/AudioBufferQueueSourceNode.js +5 -2
  297. package/lib/commonjs/core/AudioBufferQueueSourceNode.js.map +1 -1
  298. package/lib/commonjs/core/AudioContext.js +5 -8
  299. package/lib/commonjs/core/AudioContext.js.map +1 -1
  300. package/lib/commonjs/core/AudioNode.js +1 -1
  301. package/lib/commonjs/core/AudioNode.js.map +1 -1
  302. package/lib/commonjs/core/AudioParam.js +18 -11
  303. package/lib/commonjs/core/AudioParam.js.map +1 -1
  304. package/lib/commonjs/core/AudioRecorder.js +43 -55
  305. package/lib/commonjs/core/AudioRecorder.js.map +1 -1
  306. package/lib/commonjs/core/BaseAudioContext.js +61 -30
  307. package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
  308. package/lib/commonjs/core/ConvolverNode.js +37 -0
  309. package/lib/commonjs/core/ConvolverNode.js.map +1 -0
  310. package/lib/commonjs/core/DelayNode.js +17 -0
  311. package/lib/commonjs/core/DelayNode.js.map +1 -0
  312. package/lib/commonjs/core/IIRFilterNode.js +19 -0
  313. package/lib/commonjs/core/IIRFilterNode.js.map +1 -0
  314. package/lib/commonjs/core/OfflineAudioContext.js +3 -6
  315. package/lib/commonjs/core/OfflineAudioContext.js.map +1 -1
  316. package/lib/commonjs/plugin/withAudioAPI.js +46 -0
  317. package/lib/commonjs/plugin/withAudioAPI.js.map +1 -1
  318. package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -1
  319. package/lib/commonjs/system/AudioManager.js +4 -7
  320. package/lib/commonjs/system/AudioManager.js.map +1 -1
  321. package/lib/commonjs/types.js +16 -23
  322. package/lib/commonjs/types.js.map +1 -1
  323. package/lib/commonjs/utils/filePresets.js +43 -0
  324. package/lib/commonjs/utils/filePresets.js.map +1 -0
  325. package/lib/commonjs/utils/index.js +12 -27
  326. package/lib/commonjs/utils/index.js.map +1 -1
  327. package/lib/commonjs/web-core/AudioContext.js +21 -1
  328. package/lib/commonjs/web-core/AudioContext.js.map +1 -1
  329. package/lib/commonjs/web-core/ConvolverNode.js +40 -0
  330. package/lib/commonjs/web-core/ConvolverNode.js.map +1 -0
  331. package/lib/commonjs/web-core/ConvolverNodeOptions.js +6 -0
  332. package/lib/commonjs/web-core/ConvolverNodeOptions.js.map +1 -0
  333. package/lib/commonjs/web-core/DelayNode.js +17 -0
  334. package/lib/commonjs/web-core/DelayNode.js.map +1 -0
  335. package/lib/commonjs/web-core/IIRFilterNode.js +19 -0
  336. package/lib/commonjs/web-core/IIRFilterNode.js.map +1 -0
  337. package/lib/commonjs/web-core/OfflineAudioContext.js +20 -0
  338. package/lib/commonjs/web-core/OfflineAudioContext.js.map +1 -1
  339. package/lib/module/AudioAPIModule/AudioAPIModule.js +87 -0
  340. package/lib/module/AudioAPIModule/AudioAPIModule.js.map +1 -0
  341. package/lib/module/AudioAPIModule/globals.d.js +4 -0
  342. package/lib/module/AudioAPIModule/globals.d.js.map +1 -0
  343. package/lib/module/AudioAPIModule/index.js +4 -0
  344. package/lib/module/AudioAPIModule/index.js.map +1 -0
  345. package/lib/module/api.js +3 -12
  346. package/lib/module/api.js.map +1 -1
  347. package/lib/module/api.web.js +1 -0
  348. package/lib/module/api.web.js.map +1 -1
  349. package/lib/module/core/AudioBufferBaseSourceNode.js +3 -0
  350. package/lib/module/core/AudioBufferBaseSourceNode.js.map +1 -1
  351. package/lib/module/core/AudioBufferQueueSourceNode.js +5 -2
  352. package/lib/module/core/AudioBufferQueueSourceNode.js.map +1 -1
  353. package/lib/module/core/AudioContext.js +5 -8
  354. package/lib/module/core/AudioContext.js.map +1 -1
  355. package/lib/module/core/AudioNode.js +1 -1
  356. package/lib/module/core/AudioNode.js.map +1 -1
  357. package/lib/module/core/AudioParam.js +18 -11
  358. package/lib/module/core/AudioParam.js.map +1 -1
  359. package/lib/module/core/AudioRecorder.js +44 -56
  360. package/lib/module/core/AudioRecorder.js.map +1 -1
  361. package/lib/module/core/BaseAudioContext.js +63 -32
  362. package/lib/module/core/BaseAudioContext.js.map +1 -1
  363. package/lib/module/core/ConvolverNode.js +31 -0
  364. package/lib/module/core/ConvolverNode.js.map +1 -0
  365. package/lib/module/core/DelayNode.js +11 -0
  366. package/lib/module/core/DelayNode.js.map +1 -0
  367. package/lib/module/core/IIRFilterNode.js +13 -0
  368. package/lib/module/core/IIRFilterNode.js.map +1 -0
  369. package/lib/module/core/OfflineAudioContext.js +3 -6
  370. package/lib/module/core/OfflineAudioContext.js.map +1 -1
  371. package/lib/module/plugin/withAudioAPI.js +47 -1
  372. package/lib/module/plugin/withAudioAPI.js.map +1 -1
  373. package/lib/module/specs/NativeAudioAPIModule.js.map +1 -1
  374. package/lib/module/system/AudioManager.js +4 -7
  375. package/lib/module/system/AudioManager.js.map +1 -1
  376. package/lib/module/types.js +15 -22
  377. package/lib/module/types.js.map +1 -1
  378. package/lib/module/utils/filePresets.js +39 -0
  379. package/lib/module/utils/filePresets.js.map +1 -0
  380. package/lib/module/utils/index.js +10 -10
  381. package/lib/module/utils/index.js.map +1 -1
  382. package/lib/module/web-core/AudioContext.js +21 -1
  383. package/lib/module/web-core/AudioContext.js.map +1 -1
  384. package/lib/module/web-core/ConvolverNode.js +34 -0
  385. package/lib/module/web-core/ConvolverNode.js.map +1 -0
  386. package/lib/module/web-core/ConvolverNodeOptions.js +4 -0
  387. package/lib/module/web-core/ConvolverNodeOptions.js.map +1 -0
  388. package/lib/module/web-core/DelayNode.js +11 -0
  389. package/lib/module/web-core/DelayNode.js.map +1 -0
  390. package/lib/module/web-core/IIRFilterNode.js +13 -0
  391. package/lib/module/web-core/IIRFilterNode.js.map +1 -0
  392. package/lib/module/web-core/OfflineAudioContext.js +20 -0
  393. package/lib/module/web-core/OfflineAudioContext.js.map +1 -1
  394. package/lib/typescript/AudioAPIModule/AudioAPIModule.d.ts +36 -0
  395. package/lib/typescript/AudioAPIModule/AudioAPIModule.d.ts.map +1 -0
  396. package/lib/typescript/AudioAPIModule/index.d.ts +2 -0
  397. package/lib/typescript/AudioAPIModule/index.d.ts.map +1 -0
  398. package/lib/typescript/api.d.ts +3 -9
  399. package/lib/typescript/api.d.ts.map +1 -1
  400. package/lib/typescript/api.web.d.ts +1 -0
  401. package/lib/typescript/api.web.d.ts.map +1 -1
  402. package/lib/typescript/core/AudioBufferBaseSourceNode.d.ts +1 -0
  403. package/lib/typescript/core/AudioBufferBaseSourceNode.d.ts.map +1 -1
  404. package/lib/typescript/core/AudioBufferQueueSourceNode.d.ts +1 -1
  405. package/lib/typescript/core/AudioBufferQueueSourceNode.d.ts.map +1 -1
  406. package/lib/typescript/core/AudioContext.d.ts +1 -1
  407. package/lib/typescript/core/AudioContext.d.ts.map +1 -1
  408. package/lib/typescript/core/AudioNode.d.ts +2 -1
  409. package/lib/typescript/core/AudioNode.d.ts.map +1 -1
  410. package/lib/typescript/core/AudioParam.d.ts.map +1 -1
  411. package/lib/typescript/core/AudioRecorder.d.ts +13 -6
  412. package/lib/typescript/core/AudioRecorder.d.ts.map +1 -1
  413. package/lib/typescript/core/BaseAudioContext.d.ts +9 -3
  414. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  415. package/lib/typescript/core/ConvolverNode.d.ts +12 -0
  416. package/lib/typescript/core/ConvolverNode.d.ts.map +1 -0
  417. package/lib/typescript/core/DelayNode.d.ts +9 -0
  418. package/lib/typescript/core/DelayNode.d.ts.map +1 -0
  419. package/lib/typescript/core/IIRFilterNode.d.ts +5 -0
  420. package/lib/typescript/core/IIRFilterNode.d.ts.map +1 -0
  421. package/lib/typescript/core/OfflineAudioContext.d.ts +1 -1
  422. package/lib/typescript/core/OfflineAudioContext.d.ts.map +1 -1
  423. package/lib/typescript/events/types.d.ts +4 -0
  424. package/lib/typescript/events/types.d.ts.map +1 -1
  425. package/lib/typescript/interfaces.d.ts +34 -34
  426. package/lib/typescript/interfaces.d.ts.map +1 -1
  427. package/lib/typescript/plugin/withAudioAPI.d.ts +1 -0
  428. package/lib/typescript/plugin/withAudioAPI.d.ts.map +1 -1
  429. package/lib/typescript/specs/NativeAudioAPIModule.d.ts +2 -1
  430. package/lib/typescript/specs/NativeAudioAPIModule.d.ts.map +1 -1
  431. package/lib/typescript/system/AudioManager.d.ts +3 -2
  432. package/lib/typescript/system/AudioManager.d.ts.map +1 -1
  433. package/lib/typescript/types.d.ts +42 -34
  434. package/lib/typescript/types.d.ts.map +1 -1
  435. package/lib/typescript/utils/filePresets.d.ts +9 -0
  436. package/lib/typescript/utils/filePresets.d.ts.map +1 -0
  437. package/lib/typescript/utils/index.d.ts +1 -8
  438. package/lib/typescript/utils/index.d.ts.map +1 -1
  439. package/lib/typescript/web-core/AudioContext.d.ts +9 -2
  440. package/lib/typescript/web-core/AudioContext.d.ts.map +1 -1
  441. package/lib/typescript/web-core/BaseAudioContext.d.ts +7 -1
  442. package/lib/typescript/web-core/BaseAudioContext.d.ts.map +1 -1
  443. package/lib/typescript/web-core/ConvolverNode.d.ts +11 -0
  444. package/lib/typescript/web-core/ConvolverNode.d.ts.map +1 -0
  445. package/lib/typescript/web-core/ConvolverNodeOptions.d.ts +6 -0
  446. package/lib/typescript/web-core/ConvolverNodeOptions.d.ts.map +1 -0
  447. package/lib/typescript/web-core/DelayNode.d.ts +8 -0
  448. package/lib/typescript/web-core/DelayNode.d.ts.map +1 -0
  449. package/lib/typescript/web-core/IIRFilterNode.d.ts +5 -0
  450. package/lib/typescript/web-core/IIRFilterNode.d.ts.map +1 -0
  451. package/lib/typescript/web-core/OfflineAudioContext.d.ts +8 -1
  452. package/lib/typescript/web-core/OfflineAudioContext.d.ts.map +1 -1
  453. package/package.json +11 -4
  454. package/scripts/download-prebuilt-binaries.sh +61 -0
  455. package/scripts/rnaa_utils.rb +8 -0
  456. package/scripts/validate-worklets-version.js +27 -0
  457. package/src/AudioAPIModule/AudioAPIModule.ts +122 -0
  458. package/src/AudioAPIModule/globals.d.ts +33 -0
  459. package/src/AudioAPIModule/index.ts +1 -0
  460. package/src/api.ts +4 -52
  461. package/src/api.web.ts +1 -0
  462. package/src/core/AudioBufferBaseSourceNode.ts +8 -0
  463. package/src/core/AudioBufferQueueSourceNode.ts +8 -2
  464. package/src/core/AudioContext.ts +5 -8
  465. package/src/core/AudioNode.ts +4 -3
  466. package/src/core/AudioParam.ts +18 -11
  467. package/src/core/AudioRecorder.ts +63 -78
  468. package/src/core/BaseAudioContext.ts +120 -54
  469. package/src/core/ConvolverNode.ts +35 -0
  470. package/src/core/DelayNode.ts +13 -0
  471. package/src/core/IIRFilterNode.ts +25 -0
  472. package/src/core/OfflineAudioContext.ts +4 -7
  473. package/src/events/types.ts +5 -0
  474. package/src/interfaces.ts +51 -34
  475. package/src/plugin/withAudioAPI.ts +61 -0
  476. package/src/specs/NativeAudioAPIModule.ts +3 -2
  477. package/src/system/AudioManager.ts +13 -19
  478. package/src/types.ts +45 -36
  479. package/src/utils/filePresets.ts +47 -0
  480. package/src/utils/index.ts +13 -19
  481. package/src/web-core/AudioContext.tsx +40 -1
  482. package/src/web-core/BaseAudioContext.tsx +11 -1
  483. package/src/web-core/ConvolverNode.tsx +43 -0
  484. package/src/web-core/ConvolverNodeOptions.tsx +6 -0
  485. package/src/web-core/DelayNode.tsx +12 -0
  486. package/src/web-core/IIRFilterNode.tsx +25 -0
  487. package/src/web-core/OfflineAudioContext.tsx +39 -0
  488. package/android/src/main/cpp/audioapi/android/core/utils/FileUtils.h +0 -34
  489. package/android/src/main/cpp/audioapi/android/core/utils/FileUtilts.cpp +0 -133
  490. package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/FFmpegAudioFileOptions.cpp +0 -154
  491. package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/FFmpegAudioFileOptions.h +0 -41
  492. package/android/src/main/cpp/audioapi/android/core/utils/miniaudioBackend/MiniAudioFileOptions.cpp +0 -47
  493. package/android/src/main/cpp/audioapi/android/core/utils/miniaudioBackend/MiniAudioFileOptions.h +0 -28
  494. package/common/cpp/audioapi/libs/ffmpeg/INSTRUCTIONS.md +0 -32
  495. package/common/cpp/audioapi/libs/ffmpeg/create_xcframework.sh +0 -111
  496. package/common/cpp/audioapi/libs/ffmpeg/ffmpeg_setup.sh +0 -391
  497. package/ios/audioapi/ios/core/IOSAudioFileOptions.h +0 -36
  498. package/ios/audioapi/ios/core/IOSAudioFileOptions.mm +0 -140
  499. package/ios/audioapi/ios/core/IOSAudioFileWriter.mm +0 -223
  500. package/ios/audioapi/ios/core/IOSRecorderCallback.mm +0 -189
  501. package/lib/commonjs/utils/bitEnums.js +0 -33
  502. package/lib/commonjs/utils/bitEnums.js.map +0 -1
  503. package/lib/module/utils/bitEnums.js +0 -27
  504. package/lib/module/utils/bitEnums.js.map +0 -1
  505. package/lib/typescript/utils/bitEnums.d.ts +0 -4
  506. package/lib/typescript/utils/bitEnums.d.ts.map +0 -1
  507. package/metro-config/index.d.ts +0 -5
  508. package/metro-config/index.js +0 -41
  509. package/metro-config/tsconfig.json +0 -3
  510. package/src/utils/bitEnums.ts +0 -51
  511. package/common/cpp/audioapi/external/{libavcodec.xcframework → ffmpeg_ios/libavcodec.xcframework}/Info.plist +5 -5
  512. package/common/cpp/audioapi/external/{libavcodec.xcframework → ffmpeg_ios/libavcodec.xcframework}/ios-arm64/libavcodec.framework/Info.plist +0 -0
  513. package/common/cpp/audioapi/external/{libavcodec.xcframework → ffmpeg_ios/libavcodec.xcframework}/ios-arm64_x86_64-simulator/libavcodec.framework/Info.plist +0 -0
  514. package/common/cpp/audioapi/external/{libavformat.xcframework → ffmpeg_ios/libavformat.xcframework}/Info.plist +0 -0
  515. package/common/cpp/audioapi/external/{libavformat.xcframework → ffmpeg_ios/libavformat.xcframework}/ios-arm64/libavformat.framework/Info.plist +0 -0
  516. package/common/cpp/audioapi/external/{libavformat.xcframework → ffmpeg_ios/libavformat.xcframework}/ios-arm64_x86_64-simulator/libavformat.framework/Info.plist +0 -0
  517. package/common/cpp/audioapi/external/{libavutil.xcframework → ffmpeg_ios/libavutil.xcframework}/Info.plist +5 -5
  518. package/common/cpp/audioapi/external/{libavutil.xcframework → ffmpeg_ios/libavutil.xcframework}/ios-arm64/libavutil.framework/Info.plist +0 -0
  519. package/common/cpp/audioapi/external/{libavutil.xcframework → ffmpeg_ios/libavutil.xcframework}/ios-arm64_x86_64-simulator/libavutil.framework/Info.plist +0 -0
  520. package/common/cpp/audioapi/external/{libswresample.xcframework → ffmpeg_ios/libswresample.xcframework}/Info.plist +5 -5
  521. /package/common/cpp/audioapi/external/{libswresample.xcframework → ffmpeg_ios/libswresample.xcframework}/ios-arm64/libswresample.framework/Info.plist +0 -0
  522. /package/common/cpp/audioapi/external/{libswresample.xcframework → ffmpeg_ios/libswresample.xcframework}/ios-arm64_x86_64-simulator/libswresample.framework/Info.plist +0 -0
@@ -1,429 +1,510 @@
1
- #include <android/log.h>
2
- #include <cmath>
3
-
4
1
  extern "C" {
5
- #include <libavformat/avio.h>
2
+ #include <libavcodec/avcodec.h>
3
+ #include <libavformat/avformat.h>
4
+ #include <libavutil/audio_fifo.h>
5
+ #include <libavutil/opt.h>
6
+ #include <libswresample/swresample.h>
6
7
  }
7
8
 
8
9
  #include <audioapi/android/core/utils/AndroidFileWriterBackend.h>
9
- #include <audioapi/android/core/utils/ffmpegBackend/FFmpegAudioFileOptions.h>
10
+ #include <audioapi/android/core/utils/FileOptions.h>
10
11
  #include <audioapi/android/core/utils/ffmpegBackend/FFmpegFileWriter.h>
12
+ #include <audioapi/android/core/utils/ffmpegBackend/ptrs.hpp>
13
+ #include <audioapi/android/core/utils/ffmpegBackend/utils.h>
14
+ #include <audioapi/utils/AudioFileProperties.h>
15
+ #include <audioapi/utils/UnitConversion.h>
16
+
17
+ #include <algorithm>
18
+ #include <memory>
19
+ #include <string>
11
20
 
12
- constexpr double BYTES_TO_MB = 1024.0 * 1024.0;
21
+ constexpr int defaultFrameRatio = 4;
22
+ constexpr int fallbackFIFOSize = 8192;
23
+ constexpr int defaultFlushInterval = 100;
13
24
 
14
- namespace audioapi {
25
+ namespace audioapi::android::ffmpeg {
15
26
 
16
27
  FFmpegAudioFileWriter::FFmpegAudioFileWriter(
17
- float sampleRate,
18
- size_t channelCount,
19
- size_t bitRate,
20
- size_t androidFlags)
21
- : AndroidFileWriterBackend(
22
- sampleRate,
23
- channelCount,
24
- bitRate,
25
- androidFlags) {
26
- fileOptions_ = std::make_shared<FFmpegAudioFileOptions>(
27
- sampleRate, channelCount, bitRate, androidFlags);
28
+ const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry,
29
+ const std::shared_ptr<AudioFileProperties> &fileProperties)
30
+ : AndroidFileWriterBackend(audioEventHandlerRegistry, fileProperties) {
31
+ // Set flush interval from properties, limit minimum to 100ms
32
+ // to avoid people hurting themselves too much
33
+ flushIntervalMs_ = std::min(fileProperties_->androidFlushIntervalMs, defaultFlushInterval);
28
34
  }
29
35
 
30
36
  FFmpegAudioFileWriter::~FFmpegAudioFileWriter() {
31
- isFileOpen_.store(false);
32
- fileOptions_.reset();
37
+ if (isFileOpen()) {
38
+ closeFile();
39
+ }
33
40
  }
34
41
 
35
- std::string FFmpegAudioFileWriter::openFile(
36
- int32_t streamSampleRate,
42
+ /// @brief Opens a specified audio file for writing and prepares any necessary resources.
43
+ /// such as codecs, conversion buffers or circular AVIO FIFO.
44
+ /// This method should be called from the JS thread only.
45
+ /// @param streamSampleRate The sample rate of the incoming audio stream (aka microphone).
46
+ /// @param streamChannelCount The number of channels in the incoming audio stream.
47
+ /// @param streamMaxBufferSize The estimated maximum buffer size for the incoming audio stream.
48
+ /// @returns Success status with file path or Error status with message.
49
+ OpenFileResult FFmpegAudioFileWriter::openFile(
50
+ float streamSampleRate,
37
51
  int32_t streamChannelCount,
38
52
  int32_t streamMaxBufferSize) {
39
- filePath_ = fileOptions_->getFilePath("audio");
40
-
41
53
  streamSampleRate_ = streamSampleRate;
42
54
  streamChannelCount_ = streamChannelCount;
43
55
  streamMaxBufferSize_ = streamMaxBufferSize;
44
- framesWritten_.store(0);
56
+ framesWritten_.store(0, std::memory_order_release);
45
57
  nextPts_ = 0;
58
+ Result<NoneType, std::string> result = Result<NoneType, std::string>::Ok(None);
59
+ Result<std::string, std::string> filePathResult = fileoptions::getFilePath(fileProperties_);
46
60
 
47
- const AVCodec *codec = fileOptions_->getCodec();
48
- AVFormatContext *rawFormatCtx = nullptr;
49
-
50
- if (avformat_alloc_output_context2(
51
- &rawFormatCtx,
52
- nullptr,
53
- fileOptions_->getMuxerName().c_str(),
54
- filePath_.c_str()) < 0 ||
55
- !rawFormatCtx) {
56
- __android_log_print(
57
- ANDROID_LOG_ERROR,
58
- "FFmpegFileWriter",
59
- "Failed to allocate FFmpeg format context for file: %s",
60
- filePath_.c_str());
61
- return "";
61
+ if (!filePathResult.is_ok()) {
62
+ return OpenFileResult::Err(filePathResult.unwrap_err());
62
63
  }
63
64
 
64
- formatCtx_ = AVFormatContextPtr(rawFormatCtx);
65
- stream_ = avformat_new_stream(formatCtx_.get(), codec);
65
+ filePath_ = filePathResult.unwrap();
66
66
 
67
- encoderCtx_ = AVCodecContextPtr(avcodec_alloc_context3(codec));
67
+ const AVCodec *codec = getCodec(fileProperties_);
68
68
 
69
- if (!encoderCtx_) {
70
- __android_log_print(
71
- ANDROID_LOG_ERROR,
72
- "FFmpegFileWriter",
73
- "Failed to allocate FFmpeg codec context for file");
74
- return "";
69
+ if (!codec) {
70
+ return OpenFileResult::Err("Unsupported codec for the given file format");
75
71
  }
76
72
 
77
- AVDictionary *codecOptions = nullptr;
78
- size_t bitRate = fileOptions_->getBitRate();
79
- int flacCompressionLevel = fileOptions_->getFlacCompressionLevel();
80
- av_channel_layout_default(
81
- &encoderCtx_->ch_layout, fileOptions_->getChannelCount());
82
-
83
- encoderCtx_->sample_rate = fileOptions_->getSampleRate();
84
- encoderCtx_->sample_fmt = fileOptions_->getSampleFormat();
73
+ result = initializeFormatContext(codec);
85
74
 
86
- if (bitRate > 0) {
87
- encoderCtx_->bit_rate = bitRate;
75
+ if (!result.is_ok()) {
76
+ return OpenFileResult::Err(result.unwrap_err());
88
77
  }
89
78
 
90
- if (flacCompressionLevel >= 0) {
91
- av_dict_set_int(
92
- &codecOptions, "compression_level", flacCompressionLevel, 0);
93
- }
79
+ result = configureAndOpenCodec(codec);
94
80
 
95
- if (avcodec_open2(encoderCtx_.get(), codec, &codecOptions) < 0) {
96
- __android_log_print(
97
- ANDROID_LOG_ERROR,
98
- "FFmpegFileWriter",
99
- "Failed to open FFmpeg codec for file");
100
- av_dict_free(&codecOptions);
101
- return "";
81
+ if (!result.is_ok()) {
82
+ return OpenFileResult::Err(result.unwrap_err());
102
83
  }
103
84
 
104
- av_dict_free(&codecOptions);
85
+ result = initializeStream();
105
86
 
106
- if (avcodec_parameters_from_context(stream_->codecpar, encoderCtx_.get()) <
107
- 0) {
108
- __android_log_print(
109
- ANDROID_LOG_ERROR,
110
- "FFmpegFileWriter",
111
- "Failed to copy codec parameters to stream for file");
112
- return "";
87
+ if (!result.is_ok()) {
88
+ return OpenFileResult::Err(result.unwrap_err());
113
89
  }
114
90
 
115
- if (!(formatCtx_->oformat->flags & AVFMT_NOFILE)) {
116
- if (avio_open(&formatCtx_->pb, filePath_.c_str(), AVIO_FLAG_WRITE) < 0) {
117
- __android_log_print(
118
- ANDROID_LOG_ERROR,
119
- "FFmpegFileWriter",
120
- "Failed to open output file: %s",
121
- filePath_.c_str());
122
- return "";
123
- }
91
+ result = openIOAndWriteHeader();
92
+
93
+ if (!result.is_ok()) {
94
+ return OpenFileResult::Err(result.unwrap_err());
124
95
  }
125
96
 
126
- stream_->time_base =
127
- AVRational{1, static_cast<int>(encoderCtx_->sample_rate)};
97
+ result = initializeResampler(streamSampleRate, streamChannelCount);
128
98
 
129
- if (avformat_write_header(formatCtx_.get(), nullptr) < 0) {
130
- __android_log_print(
131
- ANDROID_LOG_ERROR,
132
- "FFmpegFileWriter",
133
- "Failed to write header to file: %s",
134
- filePath_.c_str());
135
- return "";
99
+ if (!result.is_ok()) {
100
+ return OpenFileResult::Err(result.unwrap_err());
136
101
  }
137
102
 
138
- frame_ = AVFramePtr(av_frame_alloc());
139
- packet_ = AVPacketPtr(av_packet_alloc());
103
+ initializeBuffers(streamMaxBufferSize);
140
104
 
141
- resampleCtx_ = SwrContextPtr(swr_alloc());
105
+ isFileOpen_.store(true, std::memory_order_release);
106
+ return OpenFileResult::Ok(filePath_);
107
+ }
142
108
 
143
- AVChannelLayout inChannelLayout;
144
- av_channel_layout_default(&inChannelLayout, streamChannelCount_);
109
+ /// @brief Closes the currently opened audio file, flushing any remaining data and finalizing the file.
110
+ /// This method should called from the JS thread only.
111
+ /// @returns CloseFileStatus indicating success with file path, size and duration, or error with message.
112
+ CloseFileResult FFmpegAudioFileWriter::closeFile() {
113
+ int result = 0;
145
114
 
146
- av_opt_set_chlayout(resampleCtx_.get(), "in_chlayout", &inChannelLayout, 0);
115
+ if (!isFileOpen()) {
116
+ return CloseFileResult::Err("File is not open");
117
+ }
147
118
 
148
- av_opt_set_chlayout(
149
- resampleCtx_.get(), "out_chlayout", &encoderCtx_->ch_layout, 0);
119
+ result = processFifo(true);
150
120
 
151
- av_opt_set_int(resampleCtx_.get(), "in_sample_rate", streamSampleRate, 0);
121
+ if (result < 0) {
122
+ auto finalStatus = finalizeOutput();
152
123
 
153
- av_opt_set_int(
154
- resampleCtx_.get(), "out_sample_rate", encoderCtx_->sample_rate, 0);
124
+ return CloseFileResult::Err(
125
+ "Failed to flush FIFO to encoder. error code: " + parseErrorCode(result) +
126
+ ", finalization status: " + (finalStatus.is_ok() ? "success" : finalStatus.unwrap_err()));
127
+ }
155
128
 
156
- av_opt_set_sample_fmt(
157
- resampleCtx_.get(), "in_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
129
+ result = avcodec_send_frame(encoderCtx_.get(), nullptr);
158
130
 
159
- av_opt_set_sample_fmt(
160
- resampleCtx_.get(), "out_sample_fmt", encoderCtx_->sample_fmt, 0);
131
+ if (result < 0) {
132
+ return CloseFileResult::Err("Failed to send EOF to encoder");
133
+ }
161
134
 
162
- if (swr_init(resampleCtx_.get()) < 0) {
163
- __android_log_print(
164
- ANDROID_LOG_ERROR,
165
- "FFmpegFileWriter",
166
- "Failed to initialize resampler for file: %s",
167
- filePath_.c_str());
168
- return "";
135
+ if (writeEncodedPackets() < 0) {
136
+ return CloseFileResult::Err("Failed to drain encoder packets");
169
137
  }
170
138
 
171
- int contextFrameRatio = 2;
139
+ return finalizeOutput();
140
+ }
172
141
 
173
- if (encoderCtx_->frame_size > 0) {
174
- contextFrameRatio = static_cast<int>(std::ceil(
175
- static_cast<double>(streamMaxBufferSize_) /
176
- static_cast<double>(encoderCtx_->frame_size)));
142
+ /// @brief Writes audio data to the currently opened file.
143
+ /// This method should be called only from the audio thread (or audio side-effect thread in the future).
144
+ /// @param data Pointer to the audio data buffer (interleaved float samples) as returned by Oboe stream.
145
+ /// @param numFrames Number of audio frames in the data buffer.
146
+ /// @returns True if the data was written successfully, false otherwise.
147
+ bool FFmpegAudioFileWriter::writeAudioData(void *data, int numFrames) {
148
+ if (!isFileOpen()) {
149
+ return false;
177
150
  }
178
151
 
179
- int fifoSize = std::max(
180
- encoderCtx_->frame_size > 0
181
- ? encoderCtx_->frame_size * contextFrameRatio * 2
182
- : streamMaxBufferSize_ * 2,
183
- 4096);
152
+ if (!resampleAndPushToFifo(data, numFrames)) {
153
+ return false;
154
+ }
184
155
 
185
- audioFifo_ = AVAudioFifoPtr(av_audio_fifo_alloc(
186
- encoderCtx_->sample_fmt, encoderCtx_->ch_layout.nb_channels, fifoSize));
156
+ framesWritten_.fetch_add(numFrames, std::memory_order_acq_rel);
157
+
158
+ if (processFifo(false) < 0) {
159
+ return false;
160
+ }
187
161
 
188
- __android_log_print(
189
- ANDROID_LOG_INFO,
190
- "FFmpegFileWriter",
191
- "Using audio FIFO size of %d frames",
192
- fifoSize);
162
+ return true;
163
+ }
193
164
 
194
- isFileOpen_.store(true);
165
+ /// @brief Initializes the FFmpeg format context for the output file.
166
+ /// @param codec The codec to be used for encoding.
167
+ /// @returns Success status or Error status with message.
168
+ Result<NoneType, std::string> FFmpegAudioFileWriter::initializeFormatContext(const AVCodec *codec) {
169
+ AVFormatContext *rawFormatCtx = nullptr;
195
170
 
196
- return filePath_;
171
+ int result = avformat_alloc_output_context2(
172
+ &rawFormatCtx, nullptr, getMuxerName(fileProperties_).c_str(), filePath_.c_str());
173
+
174
+ if (result < 0 || !rawFormatCtx) {
175
+ return Result<NoneType, std::string>::Err(
176
+ "Failed to allocate FFmpeg format context with error: " + parseErrorCode(result));
177
+ }
178
+
179
+ formatCtx_ = av_unique_ptr<AVFormatContext>(rawFormatCtx);
180
+ return Result<NoneType, std::string>::Ok(None);
197
181
  }
198
182
 
199
- std::tuple<double, double> FFmpegAudioFileWriter::closeFile() {
200
- if (!isFileOpen()) {
201
- return {0.0, 0.0};
183
+ /// @brief Configures and opens the codec context for encoding.
184
+ /// @param codec The codec to be used for encoding.
185
+ /// @returns Success status or Error status with message.
186
+ Result<NoneType, std::string> FFmpegAudioFileWriter::configureAndOpenCodec(const AVCodec *codec) {
187
+ encoderCtx_ = av_unique_ptr<AVCodecContext>(avcodec_alloc_context3(codec));
188
+
189
+ if (!encoderCtx_) {
190
+ return Result<NoneType, std::string>::Err("Failed to allocate FFmpeg codec context");
202
191
  }
203
192
 
204
- isFileOpen_.store(false);
193
+ av_channel_layout_default(&encoderCtx_->ch_layout, fileProperties_->channelCount);
194
+ encoderCtx_->sample_rate = static_cast<int>(fileProperties_->sampleRate);
195
+ encoderCtx_->sample_fmt = getSampleFormat(fileProperties_);
205
196
 
206
- const int frameSize =
207
- encoderCtx_->frame_size > 0 ? encoderCtx_->frame_size : 512;
197
+ if (fileProperties_->bitRate > 0) {
198
+ encoderCtx_->bit_rate = fileProperties_->bitRate;
199
+ }
208
200
 
209
- while (av_audio_fifo_size(audioFifo_.get()) > 0) {
210
- const int chunkSize =
211
- std::min(av_audio_fifo_size(audioFifo_.get()), frameSize);
201
+ AVDictionary *codecOptions = nullptr;
212
202
 
213
- frame_->nb_samples = chunkSize;
214
- av_channel_layout_copy(&frame_->ch_layout, &encoderCtx_->ch_layout);
215
- frame_->format = encoderCtx_->sample_fmt;
216
- frame_->sample_rate = encoderCtx_->sample_rate;
203
+ if (fileProperties_->flacCompressionLevel >= 0) {
204
+ av_dict_set_int(&codecOptions, "compression_level", fileProperties_->flacCompressionLevel, 0);
205
+ }
217
206
 
218
- if (av_frame_get_buffer(frame_.get(), 0) < 0) {
219
- __android_log_print(
220
- ANDROID_LOG_ERROR,
221
- "FFmpegFileWriter",
222
- "Failed to allocate audio frame buffer during flushing");
223
- break;
224
- }
207
+ int result = avcodec_open2(encoderCtx_.get(), codec, &codecOptions);
208
+ av_dict_free(&codecOptions);
225
209
 
226
- int fifoReadFrameCount =
227
- av_audio_fifo_read(audioFifo_.get(), (void **)frame_->data, chunkSize);
210
+ if (result < 0) {
211
+ return Result<NoneType, std::string>::Err(
212
+ "Failed to open FFmpeg codec with error: " + parseErrorCode(result));
213
+ }
228
214
 
229
- if (fifoReadFrameCount != chunkSize) {
230
- __android_log_print(
231
- ANDROID_LOG_ERROR,
232
- "FFmpegFileWriter",
233
- "Failed to read audio samples from FIFO during flushing");
234
- break;
235
- }
215
+ return Result<NoneType, std::string>::Ok(None);
216
+ }
236
217
 
237
- frame_->pts = nextPts_;
238
- nextPts_ += chunkSize;
218
+ /// @brief Initializes a new stream in the format context.
219
+ /// @returns Success status or Error status with message.
220
+ Result<NoneType, std::string> FFmpegAudioFileWriter::initializeStream() {
221
+ stream_ = avformat_new_stream(formatCtx_.get(), nullptr);
239
222
 
240
- if (avcodec_send_frame(encoderCtx_.get(), frame_.get()) < 0) {
241
- __android_log_print(
242
- ANDROID_LOG_ERROR,
243
- "FFmpegFileWriter",
244
- "Failed to send audio frame to encoder during flushing");
245
- av_frame_unref(frame_.get());
246
- break;
247
- }
223
+ if (!stream_) {
224
+ return Result<NoneType, std::string>::Err("Failed to create new stream in format context");
225
+ }
248
226
 
249
- av_frame_unref(frame_.get());
227
+ int result = avcodec_parameters_from_context(stream_->codecpar, encoderCtx_.get());
228
+
229
+ if (result < 0) {
230
+ return Result<NoneType, std::string>::Err(
231
+ "Failed to copy codec parameters to stream with error: " + parseErrorCode(result));
250
232
  }
251
233
 
252
- avcodec_send_frame(encoderCtx_.get(), nullptr);
234
+ stream_->time_base = AVRational{1, static_cast<int>(encoderCtx_->sample_rate)};
235
+ return Result<NoneType, std::string>::Ok(None);
236
+ }
253
237
 
254
- while (avcodec_receive_packet(encoderCtx_.get(), packet_.get()) == 0) {
255
- av_packet_rescale_ts(
256
- packet_.get(),
257
- AVRational{1, encoderCtx_->sample_rate},
258
- stream_->time_base);
259
- packet_->stream_index = stream_->index;
260
- av_interleaved_write_frame(formatCtx_.get(), packet_.get());
261
- av_packet_unref(packet_.get());
238
+ /// @brief Opens the file and writes the basic header (depends on the codec/format used).
239
+ /// @returns Success status or Error status with message.
240
+ Result<NoneType, std::string> FFmpegAudioFileWriter::openIOAndWriteHeader() {
241
+ int result = 0;
242
+
243
+ if (!(formatCtx_->oformat->flags & AVFMT_NOFILE)) {
244
+ result = avio_open(&formatCtx_->pb, filePath_.c_str(), AVIO_FLAG_WRITE);
245
+
246
+ if (result < 0) {
247
+ return Result<NoneType, std::string>::Err(
248
+ "Failed to open output file with error: " + parseErrorCode(result));
249
+ }
262
250
  }
263
251
 
264
- if (av_write_trailer(formatCtx_.get()) < 0) {
265
- __android_log_print(
266
- ANDROID_LOG_ERROR,
267
- "FFmpegFileWriter",
268
- "Failed to write trailer to file: %s",
269
- filePath_.c_str());
252
+ result = avformat_write_header(formatCtx_.get(), nullptr);
253
+
254
+ if (result < 0) {
255
+ return Result<NoneType, std::string>::Err("Failed to write header to file: " + filePath_);
270
256
  }
271
257
 
272
- double fileSizeInMB = avio_size(formatCtx_->pb) / BYTES_TO_MB;
273
- double durationInSeconds = getCurrentDuration();
258
+ return Result<NoneType, std::string>::Ok(None);
259
+ }
274
260
 
275
- if (formatCtx_ && formatCtx_->pb) {
276
- avio_closep(&formatCtx_->pb);
261
+ /// @brief Initializes the resampler context for audio conversion.
262
+ /// @param inputRate The sample rate of the input audio.
263
+ /// @param inputChannels The number of channels in the input audio.
264
+ /// @returns Success status or Error status with message.
265
+ Result<NoneType, std::string> FFmpegAudioFileWriter::initializeResampler(
266
+ float inputRate,
267
+ int inputChannels) {
268
+ resampleCtx_ = av_unique_ptr<SwrContext>(swr_alloc());
269
+
270
+ if (!resampleCtx_) {
271
+ return Result<NoneType, std::string>::Err("Failed to allocate resampler context");
277
272
  }
278
273
 
279
- resampleCtx_.reset();
280
- frame_.reset();
281
- packet_.reset();
282
- encoderCtx_.reset();
283
- formatCtx_.reset();
284
- audioFifo_.reset();
274
+ AVChannelLayout inChannelLayout;
275
+ av_channel_layout_default(&inChannelLayout, inputChannels);
285
276
 
286
- filePath_ = "";
287
- return {fileSizeInMB, durationInSeconds};
277
+ av_opt_set_chlayout(resampleCtx_.get(), "in_chlayout", &inChannelLayout, 0);
278
+ av_opt_set_chlayout(resampleCtx_.get(), "out_chlayout", &encoderCtx_->ch_layout, 0);
279
+
280
+ av_opt_set_int(resampleCtx_.get(), "in_sample_rate", static_cast<int64_t>(inputRate), 0);
281
+ av_opt_set_int(resampleCtx_.get(), "out_sample_rate", encoderCtx_->sample_rate, 0);
282
+
283
+ av_opt_set_sample_fmt(resampleCtx_.get(), "in_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
284
+ av_opt_set_sample_fmt(resampleCtx_.get(), "out_sample_fmt", encoderCtx_->sample_fmt, 0);
285
+
286
+ int result = swr_init(resampleCtx_.get());
287
+
288
+ if (result < 0) {
289
+ return Result<NoneType, std::string>::Err(
290
+ "Failed to initialize resampler for file: " + parseErrorCode(result));
291
+ }
292
+
293
+ return Result<NoneType, std::string>::Ok(None);
288
294
  }
289
295
 
290
- bool FFmpegAudioFileWriter::writeAudioData(void *data, int numFrames) {
291
- if (!isFileOpen()) {
292
- return false;
296
+ /// @brief Initializes frame and packet buffers as well as the audio FIFO,
297
+ /// that might be needed for storing intermediate audio data or buffering before encoding.
298
+ /// @param maxBufferSize The maximum buffer size to allocate.
299
+ void FFmpegAudioFileWriter::initializeBuffers(int32_t maxBufferSize) {
300
+ frame_ = av_unique_ptr<AVFrame>(av_frame_alloc());
301
+ packet_ = av_unique_ptr<AVPacket>(av_packet_alloc());
302
+
303
+ int frameRatio = defaultFrameRatio;
304
+ if (encoderCtx_->frame_size > 0) {
305
+ frameRatio = static_cast<int>(std::ceil(
306
+ static_cast<double>(maxBufferSize) / static_cast<double>(encoderCtx_->frame_size)));
293
307
  }
294
308
 
295
- int outputLength = av_rescale_rnd(
296
- numFrames, encoderCtx_->sample_rate, streamSampleRate_, AV_ROUND_UP);
309
+ int calculatedSize =
310
+ (encoderCtx_->frame_size > 0 ? encoderCtx_->frame_size * frameRatio
311
+ : maxBufferSize * frameRatio);
297
312
 
298
- frame_->nb_samples = outputLength;
299
- av_channel_layout_copy(&frame_->ch_layout, &encoderCtx_->ch_layout);
300
- frame_->format = encoderCtx_->sample_fmt;
301
- frame_->sample_rate = encoderCtx_->sample_rate;
313
+ int fifoSize = std::max(calculatedSize, fallbackFIFOSize);
314
+
315
+ audioFifo_ = av_unique_ptr<AVAudioFifo>(
316
+ av_audio_fifo_alloc(encoderCtx_->sample_fmt, encoderCtx_->ch_layout.nb_channels, fifoSize));
317
+ }
318
+
319
+ /// @brief Resamples input audio data and pushes it to the audio FIFO.
320
+ /// @param inputData Pointer to the input audio data.
321
+ /// @param inputFrameCount Number of input frames.
322
+ /// @returns True if successful, false otherwise.
323
+ bool FFmpegAudioFileWriter::resampleAndPushToFifo(void *inputData, int inputFrameCount) {
324
+ int result = 0;
325
+ int64_t outputLength = av_rescale_rnd(
326
+ inputFrameCount, encoderCtx_->sample_rate, static_cast<int>(streamSampleRate_), AV_ROUND_UP);
302
327
 
303
- if (av_frame_get_buffer(frame_.get(), 0) < 0) {
304
- __android_log_print(
305
- ANDROID_LOG_ERROR,
306
- "FFmpegFileWriter",
307
- "Failed to allocate audio frame buffer, outputLength: %d, format: %d, sample_rate: %d, channels: %d",
308
- outputLength,
309
- encoderCtx_->sample_fmt,
310
- encoderCtx_->sample_rate,
311
- encoderCtx_->ch_layout.nb_channels);
328
+ result = prepareFrameForEncoding(outputLength);
312
329
 
330
+ if (result < 0) {
331
+ invokeOnErrorCallback("Failed to prepare frame for resampling: " + parseErrorCode(result));
313
332
  return false;
314
333
  }
315
334
 
316
- const uint8_t *inputData[1] = {reinterpret_cast<const uint8_t *>(data)};
335
+ const uint8_t *inputs[1] = {reinterpret_cast<const uint8_t *>(inputData)};
317
336
 
318
337
  int convertedSamples = swr_convert(
319
- resampleCtx_.get(), frame_->data, outputLength, inputData, numFrames);
338
+ resampleCtx_.get(), frame_->data, static_cast<int>(outputLength), inputs, inputFrameCount);
320
339
 
321
340
  if (convertedSamples < 0) {
322
- __android_log_print(
323
- ANDROID_LOG_ERROR,
324
- "FFmpegFileWriter",
325
- "Failed to convert audio samples for file: %s",
326
- filePath_.c_str());
341
+ invokeOnErrorCallback("Failed to convert audio samples: " + parseErrorCode(convertedSamples));
327
342
  av_frame_unref(frame_.get());
328
343
  return false;
329
344
  }
330
345
 
331
- int fifoWrittenFrameCount = av_audio_fifo_write(
332
- audioFifo_.get(), (void **)frame_->data, convertedSamples);
346
+ int written = av_audio_fifo_write(
347
+ audioFifo_.get(), reinterpret_cast<void **>(frame_->data), convertedSamples);
333
348
 
334
- if (fifoWrittenFrameCount < convertedSamples) {
335
- __android_log_print(
336
- ANDROID_LOG_ERROR,
337
- "FFmpegFileWriter",
338
- "Failed to write audio samples to FIFO");
349
+ if (written < convertedSamples) {
350
+ invokeOnErrorCallback("Failed to write all samples to FIFO");
339
351
  av_frame_unref(frame_.get());
340
352
  return false;
341
353
  }
342
354
 
343
- av_frame_unref(frame_.get());
344
- const int frameSize =
345
- encoderCtx_->frame_size > 0 ? encoderCtx_->frame_size : 512;
355
+ return true;
356
+ }
346
357
 
347
- while (av_audio_fifo_size(audioFifo_.get()) >= frameSize) {
348
- frame_->nb_samples = frameSize;
349
- av_channel_layout_copy(&frame_->ch_layout, &encoderCtx_->ch_layout);
350
- frame_->format = encoderCtx_->sample_fmt;
351
- frame_->sample_rate = encoderCtx_->sample_rate;
358
+ /// @brief pushes the audio data from FIFO to the encoder in chunks,
359
+ // defined by the encoder (512 samples by default) or flushes the FIFO if requested.
360
+ /// Note: flush might be called only when writing the final data batch, otherwise
361
+ // the codec will crash (especially in case of defined size frames like AAC).
362
+ /// @param flush Indicates whether to flush the FIFO.
363
+ /// @returns 0 on success, -1 or AV_ERROR code on failure
364
+ int FFmpegAudioFileWriter::processFifo(bool flush) {
365
+ int result = 0;
366
+ int frameSize = encoderCtx_->frame_size > 0 ? encoderCtx_->frame_size : 512;
367
+
368
+ while (av_audio_fifo_size(audioFifo_.get()) >= (flush ? 1 : frameSize)) {
369
+ const int chunkSize = std::min(av_audio_fifo_size(audioFifo_.get()), frameSize);
370
+
371
+ if (prepareFrameForEncoding(chunkSize) < 0) {
372
+ invokeOnErrorCallback("Failed to prepare frame for encoding");
373
+ return -1;
374
+ }
352
375
 
353
- if (av_frame_get_buffer(frame_.get(), 0) < 0) {
354
- __android_log_print(
355
- ANDROID_LOG_ERROR,
356
- "FFmpegFileWriter",
357
- "Failed to allocate audio frame buffer");
358
- return false;
376
+ if (av_audio_fifo_read(audioFifo_.get(), reinterpret_cast<void **>(frame_->data), chunkSize) !=
377
+ chunkSize) {
378
+ invokeOnErrorCallback("Failed to read data from FIFO");
379
+ return -1;
359
380
  }
360
381
 
361
- int fifoReadFrameCount =
362
- av_audio_fifo_read(audioFifo_.get(), (void **)frame_->data, frameSize);
382
+ frame_->pts = nextPts_;
383
+ nextPts_ += chunkSize;
384
+
385
+ result = avcodec_send_frame(encoderCtx_.get(), frame_.get());
363
386
 
364
- if (fifoReadFrameCount != frameSize) {
365
- __android_log_print(
366
- ANDROID_LOG_ERROR,
367
- "FFmpegFileWriter",
368
- "Failed to read audio samples from FIFO");
369
- return false;
387
+ if (result < 0) {
388
+ invokeOnErrorCallback("Failed to send frame to encoder: " + parseErrorCode(result));
389
+ return result;
370
390
  }
371
391
 
372
- frame_->pts = nextPts_;
373
- nextPts_ += frameSize;
374
-
375
- if (avcodec_send_frame(encoderCtx_.get(), frame_.get()) < 0) {
376
- __android_log_print(
377
- ANDROID_LOG_ERROR,
378
- "FFmpegFileWriter",
379
- "Failed to send audio frame to encoder");
380
- av_frame_unref(frame_.get());
381
- return false;
392
+ result = writeEncodedPackets();
393
+
394
+ if (result < 0) {
395
+ invokeOnErrorCallback("Failed to write encoded packets: " + parseErrorCode(result));
396
+ return result;
382
397
  }
398
+ }
383
399
 
384
- while (avcodec_receive_packet(encoderCtx_.get(), packet_.get()) == 0) {
385
- av_packet_rescale_ts(
386
- packet_.get(),
387
- AVRational{1, encoderCtx_->sample_rate},
388
- stream_->time_base);
400
+ return 0;
401
+ }
389
402
 
390
- packet_->stream_index = stream_->index;
403
+ /// @brief Takes ready encoded packets from the encoder and writes them to the output file.
404
+ /// Also in order to optimize file writing vs file resilience from crashes, it periodically
405
+ /// forces the AVIO buffer to flush data to disk, by default every 0,5 second.
406
+ /// @returns 0 on success, AV_ERROR code on failure
407
+ int FFmpegAudioFileWriter::writeEncodedPackets() {
408
+ int result = 0;
409
+
410
+ while (true) {
411
+ result = avcodec_receive_packet(encoderCtx_.get(), packet_.get());
412
+
413
+ if (result == AVERROR(EAGAIN) || result == AVERROR_EOF) {
414
+ return 0;
415
+ } else if (result < 0) {
416
+ invokeOnErrorCallback("Failed to receive packet from encoder: " + parseErrorCode(result));
417
+ return result;
418
+ }
391
419
 
392
- if (av_interleaved_write_frame(formatCtx_.get(), packet_.get()) < 0) {
393
- __android_log_print(
394
- ANDROID_LOG_ERROR,
395
- "FFmpegFileWriter",
396
- "Failed to write audio packet to file");
420
+ av_packet_rescale_ts(packet_.get(), encoderCtx_->time_base, stream_->time_base);
421
+ packet_->stream_index = stream_->index;
397
422
 
398
- av_packet_unref(packet_.get());
399
- av_frame_unref(frame_.get());
400
- return false;
401
- }
423
+ result = av_interleaved_write_frame(formatCtx_.get(), packet_.get());
402
424
 
403
- av_packet_unref(packet_.get());
425
+ auto now = std::chrono::steady_clock::now();
426
+ auto elapsedMs =
427
+ std::chrono::duration_cast<std::chrono::milliseconds>(now - lastFlushTime_).count();
428
+
429
+ if (formatCtx_->pb && elapsedMs >= flushIntervalMs_) {
430
+ avio_flush(formatCtx_->pb);
431
+ lastFlushTime_ = now;
432
+ }
433
+
434
+ if (result < 0) {
435
+ return result;
404
436
  }
437
+ }
438
+ }
405
439
 
440
+ /// @brief Prepares the frame for next encoding phase,
441
+ /// if frame is same size as previously used one (99.9% cases) try to reuse it.
442
+ /// Otherwise resize the frame and in the worst case allocate new frame to use.
443
+ /// @param samplesToRead Number of samples to prepare the frame for.
444
+ /// @returns 0 on success, AV_ERROR code on failure
445
+ int FFmpegAudioFileWriter::prepareFrameForEncoding(int64_t samplesToRead) {
446
+ int result = 0;
447
+
448
+ if (frame_->data[0] && frame_->nb_samples == samplesToRead &&
449
+ av_frame_is_writable(frame_.get())) {
450
+ return 0;
451
+ }
452
+
453
+ frame_->nb_samples = static_cast<int>(samplesToRead);
454
+ frame_->format = encoderCtx_->sample_fmt;
455
+ frame_->sample_rate = encoderCtx_->sample_rate;
456
+
457
+ if (av_channel_layout_compare(&frame_->ch_layout, &encoderCtx_->ch_layout) != 0) {
458
+ av_channel_layout_uninit(&frame_->ch_layout);
459
+
460
+ result = av_channel_layout_copy(&frame_->ch_layout, &encoderCtx_->ch_layout);
461
+
462
+ if (result < 0) {
463
+ invokeOnErrorCallback("Failed to copy channel layout: " + parseErrorCode(result));
464
+ return result;
465
+ }
466
+ }
467
+
468
+ result = av_frame_make_writable(frame_.get());
469
+
470
+ if (result < 0) {
406
471
  av_frame_unref(frame_.get());
472
+
473
+ frame_->nb_samples = static_cast<int>(samplesToRead);
474
+ ;
475
+ frame_->format = encoderCtx_->sample_fmt;
476
+ frame_->sample_rate = encoderCtx_->sample_rate;
477
+ av_channel_layout_copy(&frame_->ch_layout, &encoderCtx_->ch_layout);
478
+
479
+ result = av_frame_get_buffer(frame_.get(), 0);
407
480
  }
408
481
 
409
- framesWritten_.fetch_add(numFrames);
410
- return true;
482
+ return result;
411
483
  }
412
484
 
413
- bool FFmpegAudioFileWriter::initializeConverterIfNeeded() {
414
- return false;
415
- }
485
+ /// @brief Closes the currently opened audio file, flushing any remaining data and finalizing the file.
486
+ /// Method checks the file size and duration for convenience.
487
+ /// @returns CloseFileResult indicating success or error details
488
+ CloseFileResult FFmpegAudioFileWriter::finalizeOutput() {
489
+ int result = av_write_trailer(formatCtx_.get());
416
490
 
417
- bool FFmpegAudioFileWriter::initializeEncoder() {
418
- return false;
419
- }
491
+ if (result < 0) {
492
+ return CloseFileResult::Err("Failed to write trailer: " + parseErrorCode(result));
493
+ }
420
494
 
421
- bool FFmpegAudioFileWriter::isFileOpen() {
422
- return isFileOpen_.load();
423
- }
495
+ double fileSizeInMB = 0;
496
+
497
+ if (formatCtx_->pb) {
498
+ fileSizeInMB = static_cast<double>(avio_size(formatCtx_->pb)) / MB_IN_BYTES;
499
+ avio_closep(&formatCtx_->pb);
500
+ }
501
+
502
+ double durationInSeconds = getCurrentDuration();
503
+
504
+ filePath_ = "";
505
+ isFileOpen_.store(false, std::memory_order_release);
424
506
 
425
- bool FFmpegAudioFileWriter::isConverterRequired() {
426
- return isConverterRequired_.load();
507
+ return CloseFileResult::Ok({fileSizeInMB, durationInSeconds});
427
508
  }
428
509
 
429
- } // namespace audioapi
510
+ } // namespace audioapi::android::ffmpeg