react-native-audio-api 0.10.0-nightly-c815c40-20251027 → 0.11.0-alpha.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 (213) hide show
  1. package/RNAudioAPI.podspec +5 -9
  2. package/android/build.gradle +3 -33
  3. package/android/src/main/cpp/audioapi/android/AudioAPIModule.cpp +0 -5
  4. package/android/src/main/cpp/audioapi/android/AudioAPIModule.h +0 -1
  5. package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +94 -28
  6. package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.h +28 -14
  7. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +2 -4
  8. package/android/src/main/cpp/audioapi/android/core/NativeAudioRecorder.hpp +9 -9
  9. package/android/src/main/cpp/audioapi/android/core/utils/AndroidFileWriterBackend.h +33 -0
  10. package/android/src/main/cpp/audioapi/android/core/utils/AudioDecoder.cpp +0 -6
  11. package/android/src/main/cpp/audioapi/android/core/utils/FileUtils.h +34 -0
  12. package/android/src/main/cpp/audioapi/android/core/utils/FileUtilts.cpp +133 -0
  13. package/android/src/main/cpp/audioapi/android/core/utils/MiniaudioImplementation.cpp +3 -0
  14. package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/FFmpegAudioFileOptions.cpp +154 -0
  15. package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/FFmpegAudioFileOptions.h +41 -0
  16. package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/FFmpegFileWriter.cpp +431 -0
  17. package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/FFmpegFileWriter.h +112 -0
  18. package/android/src/main/cpp/audioapi/android/core/utils/miniaudioBackend/MiniAudioFileOptions.cpp +47 -0
  19. package/android/src/main/cpp/audioapi/android/core/utils/miniaudioBackend/MiniAudioFileOptions.h +28 -0
  20. package/android/src/main/cpp/audioapi/android/core/utils/miniaudioBackend/MiniAudioFileWriter.cpp +237 -0
  21. package/android/src/main/cpp/audioapi/android/core/utils/miniaudioBackend/MiniAudioFileWriter.h +46 -0
  22. package/android/src/main/cpp/audioapi/android/system/NativeFileInfo.hpp +31 -0
  23. package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +3 -29
  24. package/android/src/main/java/com/swmansion/audioapi/system/AudioFocusListener.kt +9 -21
  25. package/android/src/main/java/com/swmansion/audioapi/system/NativeFileInfo.kt +18 -0
  26. package/android/src/main/jniLibs/arm64-v8a/libavcodec.so +0 -0
  27. package/android/src/main/jniLibs/arm64-v8a/libavformat.so +0 -0
  28. package/android/src/main/jniLibs/arm64-v8a/libavutil.so +0 -0
  29. package/android/src/main/jniLibs/arm64-v8a/libswresample.so +0 -0
  30. package/android/src/main/jniLibs/armeabi-v7a/libavcodec.so +0 -0
  31. package/android/src/main/jniLibs/armeabi-v7a/libavformat.so +0 -0
  32. package/android/src/main/jniLibs/armeabi-v7a/libavutil.so +0 -0
  33. package/android/src/main/jniLibs/armeabi-v7a/libswresample.so +0 -0
  34. package/android/src/main/jniLibs/x86/libavcodec.so +0 -0
  35. package/android/src/main/jniLibs/x86/libavformat.so +0 -0
  36. package/android/src/main/jniLibs/x86/libavutil.so +0 -0
  37. package/android/src/main/jniLibs/x86/libswresample.so +0 -0
  38. package/android/src/main/jniLibs/x86_64/libavcodec.so +0 -0
  39. package/android/src/main/jniLibs/x86_64/libavformat.so +0 -0
  40. package/android/src/main/jniLibs/x86_64/libavutil.so +0 -0
  41. package/android/src/main/jniLibs/x86_64/libswresample.so +0 -0
  42. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +2 -30
  43. package/common/cpp/audioapi/HostObjects/effects/BiquadFilterNodeHostObject.cpp +1 -1
  44. package/common/cpp/audioapi/HostObjects/inputs/AudioRecorderHostObject.cpp +80 -18
  45. package/common/cpp/audioapi/HostObjects/inputs/AudioRecorderHostObject.h +15 -6
  46. package/common/cpp/audioapi/core/AudioParam.cpp +2 -2
  47. package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +32 -69
  48. package/common/cpp/audioapi/core/effects/BiquadFilterNode.h +1 -37
  49. package/common/cpp/audioapi/core/inputs/AudioRecorder.cpp +102 -49
  50. package/common/cpp/audioapi/core/inputs/AudioRecorder.h +46 -28
  51. package/common/cpp/audioapi/core/utils/Constants.h +1 -2
  52. package/common/cpp/audioapi/core/utils/worklets/SafeIncludes.h +10 -0
  53. package/common/cpp/audioapi/external/arm64-v8a/libcrypto.a +0 -0
  54. package/common/cpp/audioapi/external/arm64-v8a/libogg.a +0 -0
  55. package/common/cpp/audioapi/external/arm64-v8a/libopus.a +0 -0
  56. package/common/cpp/audioapi/external/arm64-v8a/libopusfile.a +0 -0
  57. package/common/cpp/audioapi/external/arm64-v8a/libssl.a +0 -0
  58. package/common/cpp/audioapi/external/arm64-v8a/libvorbis.a +0 -0
  59. package/common/cpp/audioapi/external/arm64-v8a/libvorbisenc.a +0 -0
  60. package/common/cpp/audioapi/external/arm64-v8a/libvorbisfile.a +0 -0
  61. package/common/cpp/audioapi/external/armeabi-v7a/libcrypto.a +0 -0
  62. package/common/cpp/audioapi/external/armeabi-v7a/libogg.a +0 -0
  63. package/common/cpp/audioapi/external/armeabi-v7a/libopus.a +0 -0
  64. package/common/cpp/audioapi/external/armeabi-v7a/libopusfile.a +0 -0
  65. package/common/cpp/audioapi/external/armeabi-v7a/libssl.a +0 -0
  66. package/common/cpp/audioapi/external/armeabi-v7a/libvorbis.a +0 -0
  67. package/common/cpp/audioapi/external/armeabi-v7a/libvorbisenc.a +0 -0
  68. package/common/cpp/audioapi/external/armeabi-v7a/libvorbisfile.a +0 -0
  69. package/common/cpp/audioapi/external/ffmpeg_include/libavcodec/avcodec.h +2 -2
  70. package/common/cpp/audioapi/external/ffmpeg_include/libavcodec/codec.h +1 -1
  71. package/common/cpp/audioapi/external/ffmpeg_include/libavcodec/codec_desc.h +1 -1
  72. package/common/cpp/audioapi/external/ffmpeg_include/libavcodec/codec_id.h +1 -1
  73. package/common/cpp/audioapi/external/ffmpeg_include/libavcodec/codec_par.h +1 -1
  74. package/common/cpp/audioapi/external/ffmpeg_include/libavformat/avformat.h +2 -2
  75. package/common/cpp/audioapi/external/ffmpeg_include/libavutil/avutil.h +2 -2
  76. package/common/cpp/audioapi/external/iphoneos/libcrypto.a +0 -0
  77. package/common/cpp/audioapi/external/iphoneos/libogg.a +0 -0
  78. package/common/cpp/audioapi/external/iphoneos/libopus.a +0 -0
  79. package/common/cpp/audioapi/external/iphoneos/libopusfile.a +0 -0
  80. package/common/cpp/audioapi/external/iphoneos/libssl.a +0 -0
  81. package/common/cpp/audioapi/external/iphoneos/libvorbis.a +0 -0
  82. package/common/cpp/audioapi/external/iphoneos/libvorbisenc.a +0 -0
  83. package/common/cpp/audioapi/external/iphoneos/libvorbisfile.a +0 -0
  84. package/common/cpp/audioapi/external/iphonesimulator/libcrypto.a +0 -0
  85. package/common/cpp/audioapi/external/iphonesimulator/libogg.a +0 -0
  86. package/common/cpp/audioapi/external/iphonesimulator/libopus.a +0 -0
  87. package/common/cpp/audioapi/external/iphonesimulator/libopusfile.a +0 -0
  88. package/common/cpp/audioapi/external/iphonesimulator/libssl.a +0 -0
  89. package/common/cpp/audioapi/external/iphonesimulator/libvorbis.a +0 -0
  90. package/common/cpp/audioapi/external/iphonesimulator/libvorbisenc.a +0 -0
  91. package/common/cpp/audioapi/external/iphonesimulator/libvorbisfile.a +0 -0
  92. package/common/cpp/audioapi/external/libavcodec.xcframework/Info.plist +44 -0
  93. package/common/cpp/audioapi/external/libavcodec.xcframework/ios-arm64/libavcodec.framework/Info.plist +1 -0
  94. package/common/cpp/audioapi/external/libavcodec.xcframework/ios-arm64/libavcodec.framework/libavcodec +0 -0
  95. package/common/cpp/audioapi/external/libavcodec.xcframework/ios-arm64_x86_64-simulator/libavcodec.framework/Info.plist +1 -0
  96. package/common/cpp/audioapi/external/libavcodec.xcframework/ios-arm64_x86_64-simulator/libavcodec.framework/libavcodec +0 -0
  97. package/common/cpp/audioapi/external/libavformat.xcframework/Info.plist +44 -0
  98. package/common/cpp/audioapi/external/libavformat.xcframework/ios-arm64/libavformat.framework/Info.plist +1 -0
  99. package/common/cpp/audioapi/external/libavformat.xcframework/ios-arm64/libavformat.framework/libavformat +0 -0
  100. package/common/cpp/audioapi/external/libavformat.xcframework/ios-arm64_x86_64-simulator/libavformat.framework/Info.plist +1 -0
  101. package/common/cpp/audioapi/external/libavformat.xcframework/ios-arm64_x86_64-simulator/libavformat.framework/libavformat +0 -0
  102. package/common/cpp/audioapi/external/libavutil.xcframework/Info.plist +44 -0
  103. package/common/cpp/audioapi/external/libavutil.xcframework/ios-arm64/libavutil.framework/Info.plist +1 -0
  104. package/common/cpp/audioapi/external/libavutil.xcframework/ios-arm64/libavutil.framework/libavutil +0 -0
  105. package/common/cpp/audioapi/external/libavutil.xcframework/ios-arm64_x86_64-simulator/libavutil.framework/Info.plist +1 -0
  106. package/common/cpp/audioapi/external/libavutil.xcframework/ios-arm64_x86_64-simulator/libavutil.framework/libavutil +0 -0
  107. package/common/cpp/audioapi/external/libswresample.xcframework/Info.plist +44 -0
  108. package/common/cpp/audioapi/external/libswresample.xcframework/ios-arm64/libswresample.framework/Info.plist +1 -0
  109. package/common/cpp/audioapi/external/libswresample.xcframework/ios-arm64/libswresample.framework/libswresample +0 -0
  110. package/common/cpp/audioapi/external/libswresample.xcframework/ios-arm64_x86_64-simulator/libswresample.framework/Info.plist +1 -0
  111. package/common/cpp/audioapi/external/libswresample.xcframework/ios-arm64_x86_64-simulator/libswresample.framework/libswresample +0 -0
  112. package/common/cpp/audioapi/external/x86/libcrypto.a +0 -0
  113. package/common/cpp/audioapi/external/x86/libogg.a +0 -0
  114. package/common/cpp/audioapi/external/x86/libopus.a +0 -0
  115. package/common/cpp/audioapi/external/x86/libopusfile.a +0 -0
  116. package/common/cpp/audioapi/external/x86/libssl.a +0 -0
  117. package/common/cpp/audioapi/external/x86/libvorbis.a +0 -0
  118. package/common/cpp/audioapi/external/x86/libvorbisenc.a +0 -0
  119. package/common/cpp/audioapi/external/x86/libvorbisfile.a +0 -0
  120. package/common/cpp/audioapi/external/x86_64/libcrypto.a +0 -0
  121. package/common/cpp/audioapi/external/x86_64/libogg.a +0 -0
  122. package/common/cpp/audioapi/external/x86_64/libopus.a +0 -0
  123. package/common/cpp/audioapi/external/x86_64/libopusfile.a +0 -0
  124. package/common/cpp/audioapi/external/x86_64/libssl.a +0 -0
  125. package/common/cpp/audioapi/external/x86_64/libvorbis.a +0 -0
  126. package/common/cpp/audioapi/external/x86_64/libvorbisenc.a +0 -0
  127. package/common/cpp/audioapi/external/x86_64/libvorbisfile.a +0 -0
  128. package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp +3 -2
  129. package/common/cpp/audioapi/libs/ffmpeg/INSTRUCTIONS.md +32 -0
  130. package/common/cpp/audioapi/libs/ffmpeg/create_xcframework.sh +111 -0
  131. package/common/cpp/audioapi/libs/ffmpeg/ffmpeg_setup.sh +391 -0
  132. package/common/cpp/test/CMakeLists.txt +0 -3
  133. package/ios/audioapi/ios/AudioAPIModule.h +1 -2
  134. package/ios/audioapi/ios/AudioAPIModule.mm +0 -2
  135. package/ios/audioapi/ios/core/IOSAudioFileOptions.h +35 -0
  136. package/ios/audioapi/ios/core/IOSAudioFileOptions.mm +135 -0
  137. package/ios/audioapi/ios/core/IOSAudioFileWriter.h +38 -0
  138. package/ios/audioapi/ios/core/IOSAudioFileWriter.mm +187 -0
  139. package/ios/audioapi/ios/core/IOSAudioRecorder.h +18 -10
  140. package/ios/audioapi/ios/core/IOSAudioRecorder.mm +70 -28
  141. package/ios/audioapi/ios/core/NativeAudioRecorder.h +2 -6
  142. package/ios/audioapi/ios/core/NativeAudioRecorder.m +5 -73
  143. package/ios/audioapi/ios/system/AudioEngine.mm +3 -3
  144. package/ios/audioapi/ios/system/AudioSessionManager.mm +0 -9
  145. package/ios/audioapi/ios/system/LockScreenManager.h +1 -0
  146. package/ios/audioapi/ios/system/LockScreenManager.mm +19 -6
  147. package/lib/commonjs/api.js +76 -134
  148. package/lib/commonjs/api.js.map +1 -1
  149. package/lib/commonjs/core/AudioContext.js +1 -1
  150. package/lib/commonjs/core/AudioContext.js.map +1 -1
  151. package/lib/commonjs/core/AudioRecorder.js +157 -12
  152. package/lib/commonjs/core/AudioRecorder.js.map +1 -1
  153. package/lib/commonjs/core/BaseAudioContext.js +25 -16
  154. package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
  155. package/lib/commonjs/core/OfflineAudioContext.js +1 -1
  156. package/lib/commonjs/core/OfflineAudioContext.js.map +1 -1
  157. package/lib/commonjs/types.js +50 -0
  158. package/lib/commonjs/types.js.map +1 -1
  159. package/lib/commonjs/utils/bitEnums.js +33 -0
  160. package/lib/commonjs/utils/bitEnums.js.map +1 -0
  161. package/lib/commonjs/utils/index.js +21 -19
  162. package/lib/commonjs/utils/index.js.map +1 -1
  163. package/lib/module/api.js +15 -15
  164. package/lib/module/api.js.map +1 -1
  165. package/lib/module/core/AudioContext.js +2 -2
  166. package/lib/module/core/AudioContext.js.map +1 -1
  167. package/lib/module/core/AudioRecorder.js +157 -12
  168. package/lib/module/core/AudioRecorder.js.map +1 -1
  169. package/lib/module/core/BaseAudioContext.js +26 -17
  170. package/lib/module/core/BaseAudioContext.js.map +1 -1
  171. package/lib/module/core/OfflineAudioContext.js +2 -2
  172. package/lib/module/core/OfflineAudioContext.js.map +1 -1
  173. package/lib/module/types.js +46 -0
  174. package/lib/module/types.js.map +1 -1
  175. package/lib/module/utils/bitEnums.js +27 -0
  176. package/lib/module/utils/bitEnums.js.map +1 -0
  177. package/lib/module/utils/index.js +2 -15
  178. package/lib/module/utils/index.js.map +1 -1
  179. package/lib/typescript/api.d.ts +17 -18
  180. package/lib/typescript/api.d.ts.map +1 -1
  181. package/lib/typescript/core/AudioContext.d.ts.map +1 -1
  182. package/lib/typescript/core/AudioRecorder.d.ts +58 -6
  183. package/lib/typescript/core/AudioRecorder.d.ts.map +1 -1
  184. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  185. package/lib/typescript/events/types.d.ts +16 -0
  186. package/lib/typescript/events/types.d.ts.map +1 -1
  187. package/lib/typescript/interfaces.d.ts +39 -3
  188. package/lib/typescript/interfaces.d.ts.map +1 -1
  189. package/lib/typescript/types.d.ts +75 -4
  190. package/lib/typescript/types.d.ts.map +1 -1
  191. package/lib/typescript/utils/bitEnums.d.ts +4 -0
  192. package/lib/typescript/utils/bitEnums.d.ts.map +1 -0
  193. package/lib/typescript/utils/index.d.ts +2 -5
  194. package/lib/typescript/utils/index.d.ts.map +1 -1
  195. package/package.json +4 -7
  196. package/src/api.ts +18 -44
  197. package/src/core/AudioContext.ts +2 -3
  198. package/src/core/AudioRecorder.ts +190 -20
  199. package/src/core/BaseAudioContext.ts +60 -44
  200. package/src/core/OfflineAudioContext.ts +2 -2
  201. package/src/events/types.ts +18 -0
  202. package/src/interfaces.ts +47 -4
  203. package/src/types.ts +86 -4
  204. package/src/utils/bitEnums.ts +51 -0
  205. package/src/utils/index.ts +2 -22
  206. package/common/cpp/audioapi/libs/ffmpeg/relinking.md +0 -24
  207. package/common/cpp/test/src/biquad/BiquadFilterChromium.cpp +0 -389
  208. package/common/cpp/test/src/biquad/BiquadFilterChromium.h +0 -64
  209. package/common/cpp/test/src/biquad/BiquadFilterTest.cpp +0 -284
  210. package/common/cpp/test/src/biquad/BiquadFilterTest.h +0 -40
  211. package/scripts/download-prebuilt-binaries.sh +0 -52
  212. package/scripts/rnaa_utils.rb +0 -8
  213. package/scripts/validate-worklets-version.js +0 -28
@@ -0,0 +1,154 @@
1
+
2
+ #include <audioapi/android/core/utils/FileUtils.h>
3
+ #include <audioapi/android/core/utils/ffmpegBackend/FFmpegAudioFileOptions.h>
4
+
5
+ namespace audioapi {
6
+
7
+ FFmpegAudioFileOptions::FFmpegAudioFileOptions(
8
+ float sampleRate,
9
+ size_t channelCount,
10
+ size_t bitRate,
11
+ size_t flags)
12
+ : sampleRate_(sampleRate),
13
+ channelCount_(channelCount),
14
+ bitRate_(bitRate),
15
+ flags_(flags) {}
16
+
17
+ std::string FFmpegAudioFileOptions::getFileExtension() const {
18
+ android::fileutils::FileFormat format =
19
+ android::fileutils::formatFromFlags(flags_);
20
+
21
+ switch (format) {
22
+ // WAV is encoded using miniaudio, so it is not necessary here
23
+ // but lets leave it for convenience
24
+ // when using FFmpeg we will use M4A as default format
25
+ case android::fileutils::FileFormat::WAV:
26
+ return "wav";
27
+ case android::fileutils::FileFormat::CAF:
28
+ return "caf";
29
+ case android::fileutils::FileFormat::M4A:
30
+ return "m4a";
31
+ case android::fileutils::FileFormat::FLAC:
32
+ return "flac";
33
+ default:
34
+ return "m4a";
35
+ }
36
+ }
37
+
38
+ AVCodecID FFmpegAudioFileOptions::getPCMCodecID() const {
39
+ android::fileutils::BitDepth bitDepth =
40
+ android::fileutils::bitDepthFromFlags(flags_);
41
+
42
+ switch (bitDepth) {
43
+ case android::fileutils::BitDepth::BIT_16:
44
+ return AV_CODEC_ID_PCM_S16LE;
45
+ case android::fileutils::BitDepth::BIT_24:
46
+ return AV_CODEC_ID_PCM_S24LE;
47
+ case android::fileutils::BitDepth::BIT_32:
48
+ return AV_CODEC_ID_PCM_F32LE;
49
+ default:
50
+ return AV_CODEC_ID_PCM_F32LE;
51
+ }
52
+ }
53
+
54
+ AVCodecID FFmpegAudioFileOptions::getCodecID() const {
55
+ android::fileutils::FileFormat format =
56
+ android::fileutils::formatFromFlags(flags_);
57
+
58
+ switch (format) {
59
+ case android::fileutils::FileFormat::WAV:
60
+ case android::fileutils::FileFormat::CAF:
61
+ return getPCMCodecID();
62
+ case android::fileutils::FileFormat::M4A:
63
+ return AV_CODEC_ID_AAC;
64
+ case android::fileutils::FileFormat::FLAC:
65
+ return AV_CODEC_ID_FLAC;
66
+ default:
67
+ return AV_CODEC_ID_AAC;
68
+ }
69
+ }
70
+
71
+ AVSampleFormat FFmpegAudioFileOptions::getSampleFormat() const {
72
+ android::fileutils::FileFormat format =
73
+ android::fileutils::formatFromFlags(flags_);
74
+ android::fileutils::BitDepth bitDepth =
75
+ android::fileutils::bitDepthFromFlags(flags_);
76
+
77
+ if (format == android::fileutils::FileFormat::M4A) {
78
+ return AV_SAMPLE_FMT_FLTP;
79
+ }
80
+
81
+ switch (bitDepth) {
82
+ case android::fileutils::BitDepth::BIT_16:
83
+ return AV_SAMPLE_FMT_S16;
84
+ case android::fileutils::BitDepth::BIT_24:
85
+ return AV_SAMPLE_FMT_S32;
86
+ case android::fileutils::BitDepth::BIT_32:
87
+ return AV_SAMPLE_FMT_FLT;
88
+ default:
89
+ return AV_SAMPLE_FMT_FLT;
90
+ }
91
+ }
92
+
93
+ const AVCodec *FFmpegAudioFileOptions::getCodec() {
94
+ return avcodec_find_encoder(getCodecID());
95
+ }
96
+
97
+ std::string FFmpegAudioFileOptions::getFilePath(
98
+ const std::string &baseFileName) const {
99
+ std::string extension = getFileExtension();
100
+
101
+ return android::fileutils::getFilePath(
102
+ android::fileutils::directoryFromFlags(flags_), baseFileName, extension);
103
+ }
104
+
105
+ float FFmpegAudioFileOptions::getSampleRate() const {
106
+ return sampleRate_;
107
+ }
108
+
109
+ size_t FFmpegAudioFileOptions::getChannelCount() const {
110
+ return channelCount_;
111
+ }
112
+
113
+ size_t FFmpegAudioFileOptions::getBitRate() const {
114
+ android::fileutils::FileFormat format =
115
+ android::fileutils::formatFromFlags(flags_);
116
+
117
+ if (format != android::fileutils::FileFormat::M4A) {
118
+ return 0; // bit rate is not used for PCM formats
119
+ } else
120
+
121
+ return bitRate_;
122
+ }
123
+
124
+ int FFmpegAudioFileOptions::getFlacCompressionLevel() const {
125
+ android::fileutils::FileFormat format =
126
+ android::fileutils::formatFromFlags(flags_);
127
+
128
+ if (format != android::fileutils::FileFormat::FLAC) {
129
+ return -1; // compression level is not used for non-FLAC formats
130
+ }
131
+
132
+ // TODO: extract compression level from flags
133
+ return 5; // default compression level
134
+ }
135
+
136
+ std::string FFmpegAudioFileOptions::getMuxerName() const {
137
+ android::fileutils::FileFormat format =
138
+ android::fileutils::formatFromFlags(flags_);
139
+
140
+ switch (format) {
141
+ case android::fileutils::FileFormat::WAV:
142
+ return "wav";
143
+ case android::fileutils::FileFormat::CAF:
144
+ return "caf";
145
+ case android::fileutils::FileFormat::M4A:
146
+ return "mp4";
147
+ case android::fileutils::FileFormat::FLAC:
148
+ return "flac";
149
+ default:
150
+ return "mp4";
151
+ }
152
+ }
153
+
154
+ } // namespace audioapi
@@ -0,0 +1,41 @@
1
+ #pragma once
2
+
3
+ extern "C" {
4
+ #include <libavcodec/avcodec.h>
5
+ #include <libavformat/avformat.h>
6
+ #include <libswresample/swresample.h>
7
+ }
8
+
9
+ #include <cstddef>
10
+ #include <cstdint>
11
+ #include <string>
12
+
13
+ namespace audioapi {
14
+
15
+ class FFmpegAudioFileOptions {
16
+ public:
17
+ FFmpegAudioFileOptions(float sampleRate, size_t channelCount, size_t bitRate, size_t flags);
18
+ ~FFmpegAudioFileOptions() = default;
19
+
20
+ std::string getFileExtension() const;
21
+ std::string getFilePath(const std::string &baseFileName) const;
22
+
23
+ float getSampleRate() const;
24
+ size_t getChannelCount() const;
25
+
26
+ AVCodecID getPCMCodecID() const;
27
+ AVCodecID getCodecID() const;
28
+ AVSampleFormat getSampleFormat() const;
29
+ const AVCodec* getCodec();
30
+ size_t getBitRate() const;
31
+ int getFlacCompressionLevel() const;
32
+ std::string getMuxerName() const;
33
+
34
+ private:
35
+ float sampleRate_;
36
+ size_t channelCount_;
37
+ size_t flags_;
38
+ size_t bitRate_;
39
+ };
40
+
41
+ } // namespace audioapi
@@ -0,0 +1,431 @@
1
+ #include <android/log.h>
2
+ #include <cmath>
3
+ extern "C" {
4
+ #include <libavutil/log.h>
5
+ }
6
+
7
+ #include <audioapi/android/core/utils/AndroidFileWriterBackend.h>
8
+ #include <audioapi/android/core/utils/ffmpegBackend/FFmpegAudioFileOptions.h>
9
+ #include <audioapi/android/core/utils/ffmpegBackend/FFmpegFileWriter.h>
10
+
11
+ namespace audioapi {
12
+
13
+ FFmpegAudioFileWriter::FFmpegAudioFileWriter(
14
+ float sampleRate,
15
+ size_t channelCount,
16
+ size_t bitRate,
17
+ size_t androidFlags)
18
+ : AndroidFileWriterBackend(
19
+ sampleRate,
20
+ channelCount,
21
+ bitRate,
22
+ androidFlags) {
23
+ av_log_set_level(AV_LOG_DEBUG);
24
+
25
+ av_log_set_callback([](void *, int level, const char *fmt, va_list vl) {
26
+ if (level > av_log_get_level())
27
+ return;
28
+ char msg[1024];
29
+ vsnprintf(msg, sizeof(msg), fmt, vl);
30
+ __android_log_print(ANDROID_LOG_INFO, "FFmpeg", "%s", msg);
31
+ });
32
+
33
+ fileOptions_ = std::make_shared<FFmpegAudioFileOptions>(
34
+ sampleRate, channelCount, bitRate, androidFlags);
35
+ }
36
+
37
+ FFmpegAudioFileWriter::~FFmpegAudioFileWriter() {
38
+ isFileOpen_.store(false);
39
+ fileOptions_.reset();
40
+ }
41
+
42
+ void FFmpegAudioFileWriter::openFile(
43
+ int32_t streamSampleRate,
44
+ int32_t streamChannelCount,
45
+ int32_t streamMaxBufferSize) {
46
+ filePath_ = fileOptions_->getFilePath("audio");
47
+
48
+ streamSampleRate_ = streamSampleRate;
49
+ streamChannelCount_ = streamChannelCount;
50
+ streamMaxBufferSize_ = streamMaxBufferSize;
51
+ nextPts_ = 0;
52
+
53
+ const AVCodec *codec = fileOptions_->getCodec();
54
+ AVFormatContext *rawFormatCtx = nullptr;
55
+
56
+ if (avformat_alloc_output_context2(
57
+ &rawFormatCtx,
58
+ nullptr,
59
+ fileOptions_->getMuxerName().c_str(),
60
+ filePath_.c_str()) < 0 ||
61
+ !rawFormatCtx) {
62
+ __android_log_print(
63
+ ANDROID_LOG_ERROR,
64
+ "FFmpegFileWriter",
65
+ "Failed to allocate FFmpeg format context for file: %s",
66
+ filePath_.c_str());
67
+ return;
68
+ }
69
+
70
+ formatCtx_ = AVFormatContextPtr(rawFormatCtx);
71
+ stream_ = avformat_new_stream(formatCtx_.get(), codec);
72
+
73
+ encoderCtx_ = AVCodecContextPtr(avcodec_alloc_context3(codec));
74
+
75
+ if (!encoderCtx_) {
76
+ __android_log_print(
77
+ ANDROID_LOG_ERROR,
78
+ "FFmpegFileWriter",
79
+ "Failed to allocate FFmpeg codec context for file");
80
+ return;
81
+ }
82
+
83
+ AVDictionary *codecOptions = nullptr;
84
+ size_t bitRate = fileOptions_->getBitRate();
85
+ int flacCompressionLevel = fileOptions_->getFlacCompressionLevel();
86
+ av_channel_layout_default(
87
+ &encoderCtx_->ch_layout, fileOptions_->getChannelCount());
88
+
89
+ encoderCtx_->sample_rate = fileOptions_->getSampleRate();
90
+ encoderCtx_->sample_fmt = fileOptions_->getSampleFormat();
91
+
92
+ if (bitRate > 0) {
93
+ encoderCtx_->bit_rate = bitRate;
94
+ }
95
+
96
+ if (flacCompressionLevel >= 0) {
97
+ av_dict_set_int(
98
+ &codecOptions, "compression_level", flacCompressionLevel, 0);
99
+ }
100
+
101
+ if (avcodec_open2(encoderCtx_.get(), codec, &codecOptions) < 0) {
102
+ __android_log_print(
103
+ ANDROID_LOG_ERROR,
104
+ "FFmpegFileWriter",
105
+ "Failed to open FFmpeg codec for file");
106
+ av_dict_free(&codecOptions);
107
+ return;
108
+ }
109
+
110
+ av_dict_free(&codecOptions);
111
+
112
+ if (avcodec_parameters_from_context(stream_->codecpar, encoderCtx_.get()) <
113
+ 0) {
114
+ __android_log_print(
115
+ ANDROID_LOG_ERROR,
116
+ "FFmpegFileWriter",
117
+ "Failed to copy codec parameters to stream for file");
118
+ return;
119
+ }
120
+
121
+ if (!(formatCtx_->oformat->flags & AVFMT_NOFILE)) {
122
+ if (avio_open(&formatCtx_->pb, filePath_.c_str(), AVIO_FLAG_WRITE) < 0) {
123
+ __android_log_print(
124
+ ANDROID_LOG_ERROR,
125
+ "FFmpegFileWriter",
126
+ "Failed to open output file: %s",
127
+ filePath_.c_str());
128
+ return;
129
+ }
130
+ }
131
+
132
+ stream_->time_base =
133
+ AVRational{1, static_cast<int>(encoderCtx_->sample_rate)};
134
+
135
+ if (avformat_write_header(formatCtx_.get(), nullptr) < 0) {
136
+ __android_log_print(
137
+ ANDROID_LOG_ERROR,
138
+ "FFmpegFileWriter",
139
+ "Failed to write header to file: %s",
140
+ filePath_.c_str());
141
+ return;
142
+ }
143
+
144
+ frame_ = AVFramePtr(av_frame_alloc());
145
+ packet_ = AVPacketPtr(av_packet_alloc());
146
+
147
+ resampleCtx_ = SwrContextPtr(swr_alloc());
148
+
149
+ AVChannelLayout inChannelLayout;
150
+ av_channel_layout_default(&inChannelLayout, streamChannelCount_);
151
+
152
+ av_opt_set_chlayout(resampleCtx_.get(), "in_chlayout", &inChannelLayout, 0);
153
+
154
+ av_opt_set_chlayout(
155
+ resampleCtx_.get(), "out_chlayout", &encoderCtx_->ch_layout, 0);
156
+
157
+ av_opt_set_int(resampleCtx_.get(), "in_sample_rate", streamSampleRate, 0);
158
+
159
+ av_opt_set_int(
160
+ resampleCtx_.get(), "out_sample_rate", encoderCtx_->sample_rate, 0);
161
+
162
+ av_opt_set_sample_fmt(
163
+ resampleCtx_.get(), "in_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
164
+
165
+ av_opt_set_sample_fmt(
166
+ resampleCtx_.get(), "out_sample_fmt", encoderCtx_->sample_fmt, 0);
167
+
168
+ if (swr_init(resampleCtx_.get()) < 0) {
169
+ __android_log_print(
170
+ ANDROID_LOG_ERROR,
171
+ "FFmpegFileWriter",
172
+ "Failed to initialize resampler for file: %s",
173
+ filePath_.c_str());
174
+ return;
175
+ }
176
+
177
+ int contextFrameRatio = 2;
178
+
179
+ if (encoderCtx_->frame_size > 0) {
180
+ contextFrameRatio = static_cast<int>(std::ceil(
181
+ static_cast<double>(streamMaxBufferSize_) /
182
+ static_cast<double>(encoderCtx_->frame_size)));
183
+ }
184
+
185
+ int fifoSize = std::max(
186
+ encoderCtx_->frame_size > 0
187
+ ? encoderCtx_->frame_size * contextFrameRatio * 2
188
+ : streamMaxBufferSize_ * 2,
189
+ 4096);
190
+
191
+ audioFifo_ = AVAudioFifoPtr(av_audio_fifo_alloc(
192
+ encoderCtx_->sample_fmt, encoderCtx_->ch_layout.nb_channels, fifoSize));
193
+
194
+ __android_log_print(
195
+ ANDROID_LOG_INFO,
196
+ "FFmpegFileWriter",
197
+ "Using audio FIFO size of %d frames",
198
+ fifoSize);
199
+
200
+ isFileOpen_.store(true);
201
+ }
202
+
203
+ std::string FFmpegAudioFileWriter::closeFile() {
204
+ if (!isFileOpen()) {
205
+ return "";
206
+ }
207
+
208
+ isFileOpen_.store(false);
209
+
210
+ const int frameSize =
211
+ encoderCtx_->frame_size > 0 ? encoderCtx_->frame_size : 512;
212
+
213
+ while (av_audio_fifo_size(audioFifo_.get()) > 0) {
214
+ const int chunkSize =
215
+ std::min(av_audio_fifo_size(audioFifo_.get()), frameSize);
216
+
217
+ frame_->nb_samples = chunkSize;
218
+ av_channel_layout_copy(&frame_->ch_layout, &encoderCtx_->ch_layout);
219
+ frame_->format = encoderCtx_->sample_fmt;
220
+ frame_->sample_rate = encoderCtx_->sample_rate;
221
+
222
+ if (av_frame_get_buffer(frame_.get(), 0) < 0) {
223
+ __android_log_print(
224
+ ANDROID_LOG_ERROR,
225
+ "FFmpegFileWriter",
226
+ "Failed to allocate audio frame buffer during flushing");
227
+ break;
228
+ }
229
+
230
+ int fifoReadFrameCount =
231
+ av_audio_fifo_read(audioFifo_.get(), (void **)frame_->data, chunkSize);
232
+
233
+ if (fifoReadFrameCount != chunkSize) {
234
+ __android_log_print(
235
+ ANDROID_LOG_ERROR,
236
+ "FFmpegFileWriter",
237
+ "Failed to read audio samples from FIFO during flushing");
238
+ break;
239
+ }
240
+
241
+ frame_->pts = nextPts_;
242
+ nextPts_ += chunkSize;
243
+
244
+ if (avcodec_send_frame(encoderCtx_.get(), frame_.get()) < 0) {
245
+ __android_log_print(
246
+ ANDROID_LOG_ERROR,
247
+ "FFmpegFileWriter",
248
+ "Failed to send audio frame to encoder during flushing");
249
+ av_frame_unref(frame_.get());
250
+ break;
251
+ }
252
+
253
+ av_frame_unref(frame_.get());
254
+ }
255
+
256
+ avcodec_send_frame(encoderCtx_.get(), nullptr);
257
+
258
+ while (avcodec_receive_packet(encoderCtx_.get(), packet_.get()) == 0) {
259
+ av_packet_rescale_ts(
260
+ packet_.get(),
261
+ AVRational{1, encoderCtx_->sample_rate},
262
+ stream_->time_base);
263
+ packet_->stream_index = stream_->index;
264
+ av_interleaved_write_frame(formatCtx_.get(), packet_.get());
265
+ av_packet_unref(packet_.get());
266
+ }
267
+
268
+ if (av_write_trailer(formatCtx_.get()) < 0) {
269
+ __android_log_print(
270
+ ANDROID_LOG_ERROR,
271
+ "FFmpegFileWriter",
272
+ "Failed to write trailer to file: %s",
273
+ filePath_.c_str());
274
+ }
275
+
276
+ if (formatCtx_ && formatCtx_->pb) {
277
+ avio_closep(&formatCtx_->pb);
278
+ }
279
+
280
+ resampleCtx_.reset();
281
+ frame_.reset();
282
+ packet_.reset();
283
+ encoderCtx_.reset();
284
+ formatCtx_.reset();
285
+ audioFifo_.reset();
286
+
287
+ std::string closedFilePath = filePath_;
288
+ filePath_ = "";
289
+
290
+ return closedFilePath;
291
+ }
292
+
293
+ bool FFmpegAudioFileWriter::writeAudioData(void *data, int numFrames) {
294
+ if (!isFileOpen()) {
295
+ return false;
296
+ }
297
+
298
+ int outputLength = av_rescale_rnd(
299
+ numFrames, encoderCtx_->sample_rate, streamSampleRate_, AV_ROUND_UP);
300
+
301
+ frame_->nb_samples = outputLength;
302
+ av_channel_layout_copy(&frame_->ch_layout, &encoderCtx_->ch_layout);
303
+ frame_->format = encoderCtx_->sample_fmt;
304
+ frame_->sample_rate = encoderCtx_->sample_rate;
305
+
306
+ if (av_frame_get_buffer(frame_.get(), 0) < 0) {
307
+ __android_log_print(
308
+ ANDROID_LOG_ERROR,
309
+ "FFmpegFileWriter",
310
+ "Failed to allocate audio frame buffer, outputLength: %d, format: %d, sample_rate: %d, channels: %d",
311
+ outputLength,
312
+ encoderCtx_->sample_fmt,
313
+ encoderCtx_->sample_rate,
314
+ encoderCtx_->ch_layout.nb_channels);
315
+
316
+ return false;
317
+ }
318
+
319
+ const uint8_t *inputData[1] = {reinterpret_cast<const uint8_t *>(data)};
320
+
321
+ int convertedSamples = swr_convert(
322
+ resampleCtx_.get(), frame_->data, outputLength, inputData, numFrames);
323
+
324
+ if (convertedSamples < 0) {
325
+ __android_log_print(
326
+ ANDROID_LOG_ERROR,
327
+ "FFmpegFileWriter",
328
+ "Failed to convert audio samples for file: %s",
329
+ filePath_.c_str());
330
+ av_frame_unref(frame_.get());
331
+ return false;
332
+ }
333
+
334
+ int fifoWrittenFrameCount = av_audio_fifo_write(
335
+ audioFifo_.get(), (void **)frame_->data, convertedSamples);
336
+
337
+ if (fifoWrittenFrameCount < convertedSamples) {
338
+ __android_log_print(
339
+ ANDROID_LOG_ERROR,
340
+ "FFmpegFileWriter",
341
+ "Failed to write audio samples to FIFO");
342
+ av_frame_unref(frame_.get());
343
+ return false;
344
+ }
345
+
346
+ av_frame_unref(frame_.get());
347
+ const int frameSize =
348
+ encoderCtx_->frame_size > 0 ? encoderCtx_->frame_size : 512;
349
+
350
+ while (av_audio_fifo_size(audioFifo_.get()) >= frameSize) {
351
+ frame_->nb_samples = frameSize;
352
+ av_channel_layout_copy(&frame_->ch_layout, &encoderCtx_->ch_layout);
353
+ frame_->format = encoderCtx_->sample_fmt;
354
+ frame_->sample_rate = encoderCtx_->sample_rate;
355
+
356
+ if (av_frame_get_buffer(frame_.get(), 0) < 0) {
357
+ __android_log_print(
358
+ ANDROID_LOG_ERROR,
359
+ "FFmpegFileWriter",
360
+ "Failed to allocate audio frame buffer");
361
+ return false;
362
+ }
363
+
364
+ int fifoReadFrameCount =
365
+ av_audio_fifo_read(audioFifo_.get(), (void **)frame_->data, frameSize);
366
+
367
+ if (fifoReadFrameCount != frameSize) {
368
+ __android_log_print(
369
+ ANDROID_LOG_ERROR,
370
+ "FFmpegFileWriter",
371
+ "Failed to read audio samples from FIFO");
372
+ return false;
373
+ }
374
+
375
+ frame_->pts = nextPts_;
376
+ nextPts_ += frameSize;
377
+
378
+ if (avcodec_send_frame(encoderCtx_.get(), frame_.get()) < 0) {
379
+ __android_log_print(
380
+ ANDROID_LOG_ERROR,
381
+ "FFmpegFileWriter",
382
+ "Failed to send audio frame to encoder");
383
+ av_frame_unref(frame_.get());
384
+ return false;
385
+ }
386
+
387
+ while (avcodec_receive_packet(encoderCtx_.get(), packet_.get()) == 0) {
388
+ av_packet_rescale_ts(
389
+ packet_.get(),
390
+ AVRational{1, encoderCtx_->sample_rate},
391
+ stream_->time_base);
392
+
393
+ packet_->stream_index = stream_->index;
394
+
395
+ if (av_interleaved_write_frame(formatCtx_.get(), packet_.get()) < 0) {
396
+ __android_log_print(
397
+ ANDROID_LOG_ERROR,
398
+ "FFmpegFileWriter",
399
+ "Failed to write audio packet to file");
400
+
401
+ av_packet_unref(packet_.get());
402
+ av_frame_unref(frame_.get());
403
+ return false;
404
+ }
405
+
406
+ av_packet_unref(packet_.get());
407
+ }
408
+
409
+ av_frame_unref(frame_.get());
410
+ }
411
+
412
+ return true;
413
+ }
414
+
415
+ bool FFmpegAudioFileWriter::initializeConverterIfNeeded() {
416
+ return false;
417
+ }
418
+
419
+ bool FFmpegAudioFileWriter::initializeEncoder() {
420
+ return false;
421
+ }
422
+
423
+ bool FFmpegAudioFileWriter::isFileOpen() {
424
+ return isFileOpen_.load();
425
+ }
426
+
427
+ bool FFmpegAudioFileWriter::isConverterRequired() {
428
+ return isConverterRequired_.load();
429
+ }
430
+
431
+ } // namespace audioapi