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,187 @@
1
+ #import <AVFoundation/AVFoundation.h>
2
+ #import <Foundation/Foundation.h>
3
+
4
+ #include <audioapi/ios/core/IOSAudioFileOptions.h>
5
+ #include <audioapi/ios/core/IOSAudioFileWriter.h>
6
+
7
+ namespace audioapi {
8
+ IOSAudioFileWriter::IOSAudioFileWriter(float sampleRate, size_t channelCount, size_t bitRate, size_t iosFlags)
9
+ {
10
+ fileOptions_ = std::make_shared<IOSAudioFileOptions>(sampleRate, channelCount, bitRate, iosFlags);
11
+ }
12
+
13
+ IOSAudioFileWriter::~IOSAudioFileWriter()
14
+ {
15
+ fileURL_ = nil;
16
+ audioFile_ = nil;
17
+ converter_ = nil;
18
+ bufferFormat_ = nil;
19
+ }
20
+
21
+ void IOSAudioFileWriter::openFile(AVAudioFormat *bufferFormat)
22
+ {
23
+ @autoreleasepool {
24
+ if (audioFile_ != nil) {
25
+ NSLog(@"⚠️ createFileForWriting: currentAudioFile_ already exists");
26
+ return;
27
+ }
28
+
29
+ bufferFormat_ = bufferFormat;
30
+
31
+ NSError *error = nil;
32
+ NSDictionary *settings = fileOptions_->getFileSettings();
33
+ fileURL_ = getFileURL();
34
+
35
+ NSLog(@"ℹ️ Creating audio file at URL: %@", [fileURL_ absoluteString]);
36
+
37
+ audioFile_ = [[AVAudioFile alloc] initForWriting:fileURL_
38
+ settings:settings
39
+ commonFormat:AVAudioPCMFormatFloat32
40
+ interleaved:bufferFormat.interleaved
41
+ error:&error];
42
+ converter_ = [[AVAudioConverter alloc] initFromFormat:bufferFormat toFormat:[audioFile_ processingFormat]];
43
+ converter_.sampleRateConverterAlgorithm = AVSampleRateConverterAlgorithm_Normal;
44
+ converter_.sampleRateConverterQuality = AVAudioQualityMax;
45
+ converter_.primeMethod = AVAudioConverterPrimeMethod_None;
46
+
47
+ NSLog(@"buferFormat: %@ fileFormat: %@", bufferFormat, [audioFile_ processingFormat]);
48
+
49
+ if (error != nil || audioFile_ == nil) {
50
+ NSLog(@"Error creating audio file for writing: %@", [error debugDescription]);
51
+ audioFile_ = nil;
52
+ }
53
+ }
54
+ }
55
+
56
+ std::string IOSAudioFileWriter::closeFile()
57
+ {
58
+ @autoreleasepool {
59
+ std::string filePath = [[fileURL_ path] UTF8String];
60
+
61
+ if (audioFile_ == nil) {
62
+ return "";
63
+ }
64
+
65
+ // AVAudioFile automatically finalizes the file when deallocated
66
+ audioFile_ = nil;
67
+ fileURL_ = nil;
68
+ return filePath;
69
+ }
70
+ }
71
+
72
+ bool IOSAudioFileWriter::writeAudioData(const AudioBufferList *audioBufferList, int numFrames)
73
+ {
74
+ if (audioFile_ == nil) {
75
+ NSLog(@"⚠️ writeAudioData: audioFile is nil, cannot write data");
76
+ return false;
77
+ }
78
+
79
+ // TODO: not sure if this is necessary
80
+ @autoreleasepool {
81
+ NSError *error = nil;
82
+ AVAudioFormat *filePCMFormat = [audioFile_ processingFormat];
83
+
84
+ if (audioBufferList->mNumberBuffers != filePCMFormat.channelCount ||
85
+ bufferFormat_.sampleRate != filePCMFormat.sampleRate ||
86
+ bufferFormat_.interleaved != filePCMFormat.interleaved) {
87
+ int outputFrameCount = ceil(numFrames * filePCMFormat.sampleRate / bufferFormat_.sampleRate);
88
+
89
+ AVAudioPCMBuffer *inputBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:bufferFormat_
90
+ frameCapacity:(AVAudioFrameCount)numFrames];
91
+
92
+ for (int i = 0; i < bufferFormat_.channelCount; i++) {
93
+ memcpy(
94
+ inputBuffer.mutableAudioBufferList->mBuffers[i].mData,
95
+ audioBufferList->mBuffers[i].mData,
96
+ audioBufferList->mBuffers[i].mDataByteSize);
97
+ }
98
+
99
+ inputBuffer.frameLength = numFrames;
100
+ AVAudioPCMBuffer *outputBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:filePCMFormat
101
+ frameCapacity:outputFrameCount];
102
+ outputBuffer.frameLength = outputFrameCount;
103
+
104
+ AVAudioConverterInputBlock inputBlock =
105
+ ^AVAudioBuffer *_Nullable(AVAudioPacketCount inNumberOfPackets, AVAudioConverterInputStatus *outStatus)
106
+ {
107
+ // this line is probably an delusion, but for my sanity lets keep it
108
+ inNumberOfPackets = numFrames;
109
+ *outStatus = AVAudioConverterInputStatus_HaveData;
110
+ return inputBuffer;
111
+ };
112
+
113
+ [converter_ convertToBuffer:outputBuffer error:&error withInputFromBlock:inputBlock];
114
+
115
+ if (error != nil) {
116
+ NSLog(@"Error during audio conversion: %@", [error debugDescription]);
117
+ return false;
118
+ }
119
+
120
+ [audioFile_ writeFromBuffer:outputBuffer error:&error];
121
+
122
+ if (error != nil) {
123
+ NSLog(@"Error writing audio data to file: %@", [error debugDescription]);
124
+ return false;
125
+ }
126
+ } else {
127
+ AVAudioPCMBuffer *processingBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:filePCMFormat
128
+ bufferListNoCopy:audioBufferList
129
+ deallocator:NULL];
130
+
131
+ [audioFile_ writeFromBuffer:processingBuffer error:&error];
132
+
133
+ if (error != nil) {
134
+ NSLog(@"Error writing audio data to file: %@", [error debugDescription]);
135
+ return false;
136
+ }
137
+ }
138
+
139
+ return true;
140
+ }
141
+ }
142
+
143
+ NSString *IOSAudioFileWriter::getISODateStringForDirectory()
144
+ {
145
+ NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
146
+ fmt.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
147
+ fmt.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; // or local if you prefer
148
+ fmt.dateFormat = @"yyyy-MM-dd";
149
+ return [fmt stringFromDate:[NSDate date]];
150
+ }
151
+
152
+ NSString *IOSAudioFileWriter::getTimestampForFilename()
153
+ {
154
+ NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
155
+ fmt.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
156
+ fmt.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"UTC"]; // or local if you prefer
157
+ fmt.dateFormat = @"yyyyMMdd_HHmmss_SSS";
158
+ return [fmt stringFromDate:[NSDate date]];
159
+ }
160
+
161
+ NSURL *IOSAudioFileWriter::getFileURL()
162
+ {
163
+ NSError *error = nil;
164
+
165
+ NSSearchPathDirectory searchDirectory = fileOptions_->getDirectory();
166
+ NSString *directory = [NSString stringWithFormat:@"AudioAPI/%@", getISODateStringForDirectory()];
167
+
168
+ NSURL *baseURL = [[[NSFileManager defaultManager] URLsForDirectory:searchDirectory
169
+ inDomains:NSUserDomainMask] firstObject];
170
+ NSURL *dirURL = [baseURL URLByAppendingPathComponent:directory isDirectory:YES];
171
+
172
+ [[NSFileManager defaultManager] createDirectoryAtURL:dirURL
173
+ withIntermediateDirectories:YES
174
+ attributes:nil
175
+ error:&error];
176
+
177
+ if (error != nil) {
178
+ NSLog(@"Error creating directory for audio recordings: %@", [error debugDescription]);
179
+ dirURL = baseURL;
180
+ }
181
+
182
+ NSString *fileName =
183
+ [NSString stringWithFormat:@"audio_%@.%@", getTimestampForFilename(), fileOptions_->getFileExtension()];
184
+ return [dirURL URLByAppendingPathComponent:fileName];
185
+ }
186
+
187
+ } // namespace audioapi
@@ -1,8 +1,11 @@
1
1
  #pragma once
2
2
 
3
- #ifdef __OBJC__ // when compiled as Objective-C++
3
+ #ifdef __OBJC__ // when compiled as C++
4
4
  #import <NativeAudioRecorder.h>
5
- #else // when compiled as C++
5
+ #else
6
+ typedef struct objc_object AVAudioFile;
7
+ typedef struct objc_object NSURL;
8
+ typedef struct objc_object AudioBufferList;
6
9
  typedef struct objc_object NativeAudioRecorder;
7
10
  #endif // __OBJC__
8
11
 
@@ -12,22 +15,27 @@ namespace audioapi {
12
15
 
13
16
  class AudioBus;
14
17
  class CircularAudioArray;
18
+ class IOSAudioFileWriter;
19
+ class AudioEventHandlerRegistry;
15
20
 
16
21
  class IOSAudioRecorder : public AudioRecorder {
17
22
  public:
18
- IOSAudioRecorder(
19
- float sampleRate,
20
- int bufferLength,
21
- const std::shared_ptr<AudioEventHandlerRegistry>
22
- &audioEventHandlerRegistry);
23
-
23
+ IOSAudioRecorder(const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry);
24
24
  ~IOSAudioRecorder() override;
25
25
 
26
26
  void start() override;
27
- void stop() override;
27
+ std::string stop() override;
28
+
29
+ void enableFileOutput(float sampleRate, size_t channelCount, size_t bitRate, size_t iosFlags, size_t androidFlags)
30
+ override;
31
+ void disableFileOutput() override;
32
+
33
+ void pause() override;
34
+ void resume() override;
28
35
 
29
36
  private:
30
- NativeAudioRecorder *audioRecorder_;
37
+ std::shared_ptr<IOSAudioFileWriter> fileWriter_;
38
+ NativeAudioRecorder *nativeRecorder_;
31
39
  };
32
40
 
33
41
  } // namespace audioapi
@@ -1,70 +1,112 @@
1
1
  #import <AVFoundation/AVFoundation.h>
2
+ #import <Foundation/Foundation.h>
3
+ #include <unordered_map>
2
4
 
3
5
  #include <audioapi/core/utils/Constants.h>
4
6
  #include <audioapi/dsp/VectorMath.h>
5
7
  #include <audioapi/events/AudioEventHandlerRegistry.h>
8
+ #include <audioapi/ios/core/IOSAudioFileWriter.h>
6
9
  #include <audioapi/ios/core/IOSAudioRecorder.h>
7
10
  #include <audioapi/utils/AudioArray.h>
8
11
  #include <audioapi/utils/AudioBus.h>
9
12
  #include <audioapi/utils/CircularAudioArray.h>
10
13
  #include <audioapi/utils/CircularOverflowableAudioArray.h>
11
- #include <unordered_map>
12
14
 
13
15
  namespace audioapi {
14
16
 
15
- IOSAudioRecorder::IOSAudioRecorder(
16
- float sampleRate,
17
- int bufferLength,
18
- const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry)
19
- : AudioRecorder(sampleRate, bufferLength, audioEventHandlerRegistry)
20
- {
21
- AudioReceiverBlock audioReceiverBlock = ^(const AudioBufferList *inputBuffer, int numFrames) {
22
- if (isRunning_.load()) {
23
- auto *inputChannel = static_cast<float *>(inputBuffer->mBuffers[0].mData);
24
- writeToBuffers(inputChannel, numFrames);
25
- }
17
+ // AudioReceiverBlock audioReceiverBlock = ^(const AudioBufferList *inputBuffer, int numFrames) {
18
+ // if (isRunning_.load()) {
19
+ // auto *inputChannel = static_cast<float *>(inputBuffer->mBuffers[0].mData);
20
+ // writeToBuffers(inputChannel, numFrames);
21
+ // }
22
+
23
+ // while (circularBuffer_->getNumberOfAvailableFrames() >= bufferLength_) {
24
+ // auto bus = std::make_shared<AudioBus>(bufferLength_, 1, sampleRate_);
25
+ // auto *outputChannel = bus->getChannel(0)->getData();
26
26
 
27
- while (circularBuffer_->getNumberOfAvailableFrames() >= bufferLength_) {
28
- auto bus = std::make_shared<AudioBus>(bufferLength_, 1, sampleRate_);
29
- auto *outputChannel = bus->getChannel(0)->getData();
27
+ // circularBuffer_->pop_front(outputChannel, bufferLength_);
30
28
 
31
- circularBuffer_->pop_front(outputChannel, bufferLength_);
29
+ // invokeOnAudioReadyCallback(bus, bufferLength_);
30
+ // }
31
+ // };
32
32
 
33
- invokeOnAudioReadyCallback(bus, bufferLength_);
33
+ IOSAudioRecorder::IOSAudioRecorder(const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry)
34
+ : AudioRecorder(audioEventHandlerRegistry), fileWriter_(nullptr)
35
+ {
36
+ AudioReceiverBlock receiverBlock = ^(const AudioBufferList *inputBuffer, int numFrames) {
37
+ if (usesFileOutput()) {
38
+ fileWriter_->writeAudioData(inputBuffer, numFrames);
34
39
  }
35
40
  };
36
41
 
37
- audioRecorder_ = [[NativeAudioRecorder alloc] initWithReceiverBlock:audioReceiverBlock
38
- bufferLength:bufferLength
39
- sampleRate:sampleRate];
42
+ nativeRecorder_ = [[NativeAudioRecorder alloc] initWithReceiverBlock:receiverBlock];
40
43
  }
41
44
 
42
45
  IOSAudioRecorder::~IOSAudioRecorder()
43
46
  {
44
47
  stop();
45
- [audioRecorder_ cleanup];
48
+ [nativeRecorder_ cleanup];
46
49
  }
47
50
 
48
51
  void IOSAudioRecorder::start()
49
52
  {
50
- if (isRunning_.load()) {
53
+ if (isRecording()) {
51
54
  return;
52
55
  }
53
56
 
54
- [audioRecorder_ start];
57
+ if (usesFileOutput()) {
58
+ fileWriter_->openFile([nativeRecorder_ getInputFormat]);
59
+ }
60
+
61
+ if (usesCallback()) {
62
+ // TODO: create circular buffer and converter?
63
+ }
64
+
65
+ if (isConnected()) {
66
+ // TODO: set adapter node properties?
67
+ }
68
+
69
+ [nativeRecorder_ start];
55
70
  isRunning_.store(true);
56
71
  }
57
72
 
58
- void IOSAudioRecorder::stop()
73
+ std::string IOSAudioRecorder::stop()
59
74
  {
60
- if (!isRunning_.load()) {
61
- return;
75
+ if (!isRecording()) {
76
+ return std::string("");
62
77
  }
63
78
 
79
+ [nativeRecorder_ stop];
64
80
  isRunning_.store(false);
65
- [audioRecorder_ stop];
66
81
 
67
- sendRemainingData();
82
+ // TODO: send remaining data?
83
+
84
+ if (usesFileOutput()) {
85
+ return fileWriter_->closeFile();
86
+ }
87
+
88
+ return std::string("");
68
89
  }
69
90
 
91
+ void IOSAudioRecorder::enableFileOutput(
92
+ float sampleRate,
93
+ size_t channelCount,
94
+ size_t bitRate,
95
+ size_t iosFlags,
96
+ size_t androidFlags)
97
+ {
98
+ fileOutputEnabled_.store(true);
99
+ fileWriter_ = std::make_shared<IOSAudioFileWriter>(sampleRate, channelCount, bitRate, iosFlags);
100
+ }
101
+
102
+ void IOSAudioRecorder::disableFileOutput()
103
+ {
104
+ fileOutputEnabled_.store(false);
105
+ fileWriter_ = nullptr;
106
+ }
107
+
108
+ void IOSAudioRecorder::pause() {}
109
+
110
+ void IOSAudioRecorder::resume() {}
111
+
70
112
  } // namespace audioapi
@@ -14,13 +14,9 @@ typedef void (^AudioReceiverBlock)(const AudioBufferList *inputBuffer, int numFr
14
14
  @property (nonatomic, copy) AVAudioSinkNodeReceiverBlock receiverSinkBlock;
15
15
  @property (nonatomic, copy) AudioReceiverBlock receiverBlock;
16
16
 
17
- @property (nonatomic, strong) AVAudioConverter *audioConverter;
18
- @property (nonatomic, strong) AVAudioFormat *inputFormat;
19
- @property (nonatomic, strong) AVAudioFormat *outputFormat;
17
+ - (instancetype)initWithReceiverBlock:(AudioReceiverBlock)receiverBlock;
20
18
 
21
- - (instancetype)initWithReceiverBlock:(AudioReceiverBlock)receiverBlock
22
- bufferLength:(int)bufferLength
23
- sampleRate:(float)sampleRate;
19
+ - (AVAudioFormat *)getInputFormat;
24
20
 
25
21
  - (void)start;
26
22
 
@@ -5,40 +5,18 @@
5
5
  @implementation NativeAudioRecorder
6
6
 
7
7
  - (instancetype)initWithReceiverBlock:(AudioReceiverBlock)receiverBlock
8
- bufferLength:(int)bufferLength
9
- sampleRate:(float)sampleRate
10
8
  {
11
9
  if (self = [super init]) {
12
- self.bufferLength = bufferLength;
13
- self.sampleRate = sampleRate;
14
-
15
10
  self.receiverBlock = [receiverBlock copy];
16
11
 
17
- float devicePrefferedSampleRate = [[AVAudioSession sharedInstance] sampleRate];
18
-
19
- if (!devicePrefferedSampleRate) {
20
- NSError *error;
21
- devicePrefferedSampleRate = sampleRate;
22
-
23
- [[AVAudioSession sharedInstance] setPreferredSampleRate:sampleRate error:&error];
24
- }
25
-
26
- self.inputFormat = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32
27
- sampleRate:devicePrefferedSampleRate
28
- channels:1
29
- interleaved:NO];
30
- self.outputFormat = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32
31
- sampleRate:sampleRate
32
- channels:1
33
- interleaved:NO];
34
- self.audioConverter = [[AVAudioConverter alloc] initFromFormat:self.inputFormat toFormat:self.outputFormat];
35
-
36
12
  __weak typeof(self) weakSelf = self;
37
13
  self.receiverSinkBlock = ^OSStatus(
38
14
  const AudioTimeStamp *_Nonnull timestamp,
39
15
  AVAudioFrameCount frameCount,
40
16
  const AudioBufferList *_Nonnull inputData) {
41
- return [weakSelf processAudioInput:inputData withFrameCount:frameCount atTimestamp:timestamp];
17
+ weakSelf.receiverBlock(inputData, frameCount);
18
+
19
+ return kAudioServicesNoError;
42
20
  };
43
21
 
44
22
  self.sinkNode = [[AVAudioSinkNode alloc] initWithReceiverBlock:self.receiverSinkBlock];
@@ -47,55 +25,9 @@
47
25
  return self;
48
26
  }
49
27
 
50
- - (OSStatus)processAudioInput:(const AudioBufferList *)inputData
51
- withFrameCount:(AVAudioFrameCount)frameCount
52
- atTimestamp:(const AudioTimeStamp *)timestamp
28
+ - (AVAudioFormat *)getInputFormat
53
29
  {
54
- float inputSampleRate = self.inputFormat.sampleRate;
55
- float outputSampleRate = self.outputFormat.sampleRate;
56
-
57
- if (inputSampleRate != outputSampleRate) {
58
- AVAudioPCMBuffer *inputBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:self.inputFormat
59
- frameCapacity:frameCount];
60
- memcpy(
61
- inputBuffer.mutableAudioBufferList->mBuffers[0].mData,
62
- inputData->mBuffers[0].mData,
63
- inputData->mBuffers[0].mDataByteSize);
64
- inputBuffer.frameLength = frameCount;
65
-
66
- int outputFrameCount = frameCount * outputSampleRate / inputSampleRate;
67
-
68
- AVAudioPCMBuffer *outputBuffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:self.audioConverter.outputFormat
69
- frameCapacity:outputFrameCount];
70
-
71
- NSError *error = nil;
72
- AVAudioConverterInputBlock inputBlock =
73
- ^AVAudioBuffer *_Nullable(AVAudioPacketCount inNumberOfPackets, AVAudioConverterInputStatus *outStatus)
74
- {
75
- *outStatus = AVAudioConverterInputStatus_HaveData;
76
- return inputBuffer;
77
- };
78
-
79
- /// IMPORTANT: AVAudioConverter leaks memory without autorelease pool
80
- /// more details here: https://github.com/poneciak57/AVAudioConverter-memory-leak-repro-electric-boogaloo
81
- /// we can try to remove it in the future or refactor to reuse buffers to minimize allocations
82
- @autoreleasepool {
83
- [self.audioConverter convertToBuffer:outputBuffer error:&error withInputFromBlock:inputBlock];
84
- }
85
-
86
- if (error) {
87
- NSLog(@"Error during audio conversion: %@", error.localizedDescription);
88
- return kAudioServicesBadSpecifierSizeError;
89
- }
90
-
91
- self.receiverBlock(outputBuffer.audioBufferList, outputBuffer.frameLength);
92
-
93
- return kAudioServicesNoError;
94
- }
95
-
96
- self.receiverBlock(inputData, frameCount);
97
-
98
- return kAudioServicesNoError;
30
+ return [AudioEngine.sharedInstance.audioEngine.inputNode inputFormatForBus:0];
99
31
  }
100
32
 
101
33
  - (void)start
@@ -118,9 +118,9 @@ static AudioEngine *_sharedInstance = nil;
118
118
  - (void)stopEngine
119
119
  {
120
120
  NSLog(@"[AudioEngine] stopEngine");
121
- if (![self.audioEngine isRunning]) {
122
- return;
123
- }
121
+ // if (![self.audioEngine isRunning]) {
122
+ // return;
123
+ // }
124
124
 
125
125
  self.isSupposedToBeRunning = false;
126
126
  [self.audioEngine stop];
@@ -213,15 +213,6 @@
213
213
 
214
214
  - (void)requestRecordingPermissions:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
215
215
  {
216
- id value = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSMicrophoneUsageDescription"];
217
- // if there is no entry NSMicrophoneUsageDescription calling requestRecordPermission will quit an app
218
- if (value == nil) {
219
- reject(
220
- nil,
221
- @"There is no NSMicrophoneUsageDescription entry in info.plist file. App cannot access microphone without it.",
222
- nil);
223
- return;
224
- }
225
216
  if (@available(iOS 17, *)) {
226
217
  [AVAudioSession.sharedInstance requestRecordPermission:^(BOOL granted) {
227
218
  if (granted) {
@@ -12,6 +12,7 @@
12
12
 
13
13
  @property (nonatomic, weak) MPNowPlayingInfoCenter *playingInfoCenter;
14
14
  @property (nonatomic, copy) NSString *artworkUrl;
15
+ @property (nonatomic, assign) bool isReceivingRemoteCommands;
15
16
 
16
17
  - (instancetype)initWithAudioAPIModule:(AudioAPIModule *)audioAPIModule;
17
18
  - (void)cleanup;
@@ -19,28 +19,40 @@
19
19
  if (self = [super init]) {
20
20
  self.audioAPIModule = audioAPIModule;
21
21
  self.playingInfoCenter = [MPNowPlayingInfoCenter defaultCenter];
22
+ self.isReceivingRemoteCommands = false;
23
+ }
24
+
25
+ return self;
26
+ }
22
27
 
28
+ - (void)toggleRemoteCommands:(bool)enable
29
+ {
30
+ if (enable && !self.isReceivingRemoteCommands) {
31
+ self.isReceivingRemoteCommands = true;
23
32
  dispatch_async(dispatch_get_main_queue(), ^{
24
33
  [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
25
34
  });
35
+ return;
36
+ } else if (!enable && self.isReceivingRemoteCommands) {
37
+ self.isReceivingRemoteCommands = false;
38
+ dispatch_async(dispatch_get_main_queue(), ^{
39
+ [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
40
+ });
41
+ return;
26
42
  }
27
-
28
- return self;
29
43
  }
30
44
 
31
45
  - (void)cleanup
32
46
  {
33
47
  NSLog(@"[LockScreenManager] cleanup");
48
+ [self toggleRemoteCommands:false];
34
49
  [self resetLockScreenInfo];
35
-
36
- dispatch_async(dispatch_get_main_queue(), ^{
37
- [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
38
- });
39
50
  }
40
51
 
41
52
  - (void)setLockScreenInfo:(NSDictionary *)info
42
53
  {
43
54
  self.playingInfoCenter = [MPNowPlayingInfoCenter defaultCenter];
55
+ [self toggleRemoteCommands:true];
44
56
 
45
57
  // now playing info(lock screen info)
46
58
  NSMutableDictionary *lockScreenInfoDict;
@@ -79,6 +91,7 @@
79
91
 
80
92
  - (void)resetLockScreenInfo
81
93
  {
94
+ [self toggleRemoteCommands:false];
82
95
  self.playingInfoCenter = [MPNowPlayingInfoCenter defaultCenter];
83
96
  self.playingInfoCenter.nowPlayingInfo = nil;
84
97
  self.artworkUrl = nil;