react-native-audio-api 0.11.0-nightly-52d0b79-20251216 → 0.11.0-nightly-a2a703b-20251217
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.
- package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +1 -1
- package/android/src/oldarch/NativeAudioAPIModuleSpec.java +100 -80
- package/ios/audioapi/ios/core/IOSAudioRecorder.mm +3 -2
- package/ios/audioapi/ios/core/NativeAudioRecorder.m +1 -1
- package/ios/audioapi/ios/core/utils/FileOptions.h +2 -0
- package/ios/audioapi/ios/system/AudioEngine.mm +12 -1
- package/ios/audioapi/ios/system/NotificationManager.mm +15 -9
- package/package.json +1 -1
|
@@ -111,7 +111,7 @@ Result<std::string, std::string> AndroidAudioRecorder::start() {
|
|
|
111
111
|
std::scoped_lock startLock(callbackMutex_, fileWriterMutex_, adapterNodeMutex_);
|
|
112
112
|
|
|
113
113
|
if (isRecording()) {
|
|
114
|
-
return Result<std::string, std::string>::
|
|
114
|
+
return Result<std::string, std::string>::Err("Recorder is already recording");
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
auto streamResult = openAudioStream();
|
|
@@ -10,83 +10,103 @@
|
|
|
10
10
|
* @nolint
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
13
|
+
package com.swmansion.audioapi;
|
|
14
|
+
|
|
15
|
+
import com.facebook.proguard.annotations.DoNotStrip;
|
|
16
|
+
import com.facebook.react.bridge.Promise;
|
|
17
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
18
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
19
|
+
import com.facebook.react.bridge.ReactMethod;
|
|
20
|
+
import com.facebook.react.bridge.ReadableArray;
|
|
21
|
+
import com.facebook.react.bridge.ReadableMap;
|
|
22
|
+
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
|
|
23
|
+
import javax.annotation.Nonnull;
|
|
24
|
+
|
|
25
|
+
public abstract class NativeAudioAPIModuleSpec extends ReactContextBaseJavaModule implements TurboModule {
|
|
26
|
+
public static final String NAME = "AudioAPIModule";
|
|
27
|
+
|
|
28
|
+
public NativeAudioAPIModuleSpec(ReactApplicationContext reactContext) {
|
|
29
|
+
super(reactContext);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@Override
|
|
33
|
+
public @Nonnull String getName() {
|
|
34
|
+
return NAME;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
38
|
+
@DoNotStrip
|
|
39
|
+
public abstract boolean install();
|
|
40
|
+
|
|
41
|
+
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
42
|
+
@DoNotStrip
|
|
43
|
+
public abstract double getDevicePreferredSampleRate();
|
|
44
|
+
|
|
45
|
+
@ReactMethod
|
|
46
|
+
@DoNotStrip
|
|
47
|
+
public abstract void setAudioSessionActivity(boolean enabled, Promise promise);
|
|
48
|
+
|
|
49
|
+
@ReactMethod
|
|
50
|
+
@DoNotStrip
|
|
51
|
+
public abstract void setAudioSessionOptions(String category, String mode, ReadableArray options, boolean allowHaptics);
|
|
52
|
+
|
|
53
|
+
@ReactMethod
|
|
54
|
+
@DoNotStrip
|
|
55
|
+
public abstract void disableSessionManagement();
|
|
56
|
+
|
|
57
|
+
@ReactMethod
|
|
58
|
+
@DoNotStrip
|
|
59
|
+
public abstract void observeAudioInterruptions(boolean enabled);
|
|
60
|
+
|
|
61
|
+
@ReactMethod
|
|
62
|
+
@DoNotStrip
|
|
63
|
+
public abstract void activelyReclaimSession(boolean enabled);
|
|
64
|
+
|
|
65
|
+
@ReactMethod
|
|
66
|
+
@DoNotStrip
|
|
67
|
+
public abstract void observeVolumeChanges(boolean enabled);
|
|
68
|
+
|
|
69
|
+
@ReactMethod
|
|
70
|
+
@DoNotStrip
|
|
71
|
+
public abstract void requestRecordingPermissions(Promise promise);
|
|
72
|
+
|
|
73
|
+
@ReactMethod
|
|
74
|
+
@DoNotStrip
|
|
75
|
+
public abstract void checkRecordingPermissions(Promise promise);
|
|
76
|
+
|
|
77
|
+
@ReactMethod
|
|
78
|
+
@DoNotStrip
|
|
79
|
+
public abstract void requestNotificationPermissions(Promise promise);
|
|
80
|
+
|
|
81
|
+
@ReactMethod
|
|
82
|
+
@DoNotStrip
|
|
83
|
+
public abstract void checkNotificationPermissions(Promise promise);
|
|
84
|
+
|
|
85
|
+
@ReactMethod
|
|
86
|
+
@DoNotStrip
|
|
87
|
+
public abstract void getDevicesInfo(Promise promise);
|
|
88
|
+
|
|
89
|
+
@ReactMethod
|
|
90
|
+
@DoNotStrip
|
|
91
|
+
public abstract void registerNotification(String type, String key, Promise promise);
|
|
92
|
+
|
|
93
|
+
@ReactMethod
|
|
94
|
+
@DoNotStrip
|
|
95
|
+
public abstract void showNotification(String key, ReadableMap options, Promise promise);
|
|
96
|
+
|
|
97
|
+
@ReactMethod
|
|
98
|
+
@DoNotStrip
|
|
99
|
+
public abstract void updateNotification(String key, ReadableMap options, Promise promise);
|
|
100
|
+
|
|
101
|
+
@ReactMethod
|
|
102
|
+
@DoNotStrip
|
|
103
|
+
public abstract void hideNotification(String key, Promise promise);
|
|
104
|
+
|
|
105
|
+
@ReactMethod
|
|
106
|
+
@DoNotStrip
|
|
107
|
+
public abstract void unregisterNotification(String key, Promise promise);
|
|
108
|
+
|
|
109
|
+
@ReactMethod
|
|
110
|
+
@DoNotStrip
|
|
111
|
+
public abstract void isNotificationActive(String key, Promise promise);
|
|
112
|
+
}
|
|
@@ -74,7 +74,7 @@ IOSAudioRecorder::~IOSAudioRecorder()
|
|
|
74
74
|
Result<std::string, std::string> IOSAudioRecorder::start()
|
|
75
75
|
{
|
|
76
76
|
if (isRecording()) {
|
|
77
|
-
return Result<std::string, std::string>::Err("
|
|
77
|
+
return Result<std::string, std::string>::Err("Recorder is already recording");
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
std::scoped_lock startLock(callbackMutex_, fileWriterMutex_, adapterNodeMutex_);
|
|
@@ -147,7 +147,8 @@ Result<std::tuple<std::string, double, double>, std::string> IOSAudioRecorder::s
|
|
|
147
147
|
double outputDuration = 0;
|
|
148
148
|
|
|
149
149
|
if (isIdle()) {
|
|
150
|
-
return Result<std::tuple<std::string, double, double>, std::string>::Err(
|
|
150
|
+
return Result<std::tuple<std::string, double, double>, std::string>::Err(
|
|
151
|
+
"Recorder is not in recording state.");
|
|
151
152
|
}
|
|
152
153
|
|
|
153
154
|
state_.store(RecorderState::Idle, std::memory_order_release);
|
|
@@ -96,8 +96,8 @@ static inline uint32_t nextPowerOfTwo(uint32_t x)
|
|
|
96
96
|
{
|
|
97
97
|
AudioEngine *audioEngine = [AudioEngine sharedInstance];
|
|
98
98
|
assert(audioEngine != nil);
|
|
99
|
-
[audioEngine stopIfPossible];
|
|
100
99
|
[audioEngine detachInputNode];
|
|
100
|
+
[audioEngine stopIfPossible];
|
|
101
101
|
|
|
102
102
|
// This makes sure that the engine releases the input properly when we no longer need it
|
|
103
103
|
// (i.e. no more misleading dot)
|
|
@@ -145,6 +145,18 @@ static AudioEngine *_sharedInstance = nil;
|
|
|
145
145
|
/// @brief Rebuilds the audio engine by re-attaching and re-connecting all source nodes and input node.
|
|
146
146
|
- (void)rebuildAudioEngine
|
|
147
147
|
{
|
|
148
|
+
if (self.audioEngine != nil) {
|
|
149
|
+
for (id sourceNodeId in self.sourceNodes) {
|
|
150
|
+
AVAudioSourceNode *sourceNode = [self.sourceNodes valueForKey:sourceNodeId];
|
|
151
|
+
|
|
152
|
+
[self.audioEngine detachNode:sourceNode];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (self.inputNode) {
|
|
156
|
+
[self.audioEngine detachNode:self.inputNode];
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
148
160
|
self.audioEngine = [[AVAudioEngine alloc] init];
|
|
149
161
|
|
|
150
162
|
for (id sourceNodeId in self.sourceNodes) {
|
|
@@ -175,7 +187,6 @@ static AudioEngine *_sharedInstance = nil;
|
|
|
175
187
|
}
|
|
176
188
|
|
|
177
189
|
if (self.state == AudioEngineState::AudioEngineStateInterrupted) {
|
|
178
|
-
NSLog(@"[AudioEngine] rebuilding after interruption");
|
|
179
190
|
[self.audioEngine stop];
|
|
180
191
|
[self.audioEngine reset];
|
|
181
192
|
[self rebuildAudioEngine];
|
|
@@ -117,8 +117,10 @@ static NSString *NotificationManagerContext = @"NotificationManagerContext";
|
|
|
117
117
|
[notification.userInfo[AVAudioSessionInterruptionOptionKey] integerValue];
|
|
118
118
|
|
|
119
119
|
if (interruptionType == AVAudioSessionInterruptionTypeBegan) {
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
121
|
+
[audioEngine onInterruptionBegin];
|
|
122
|
+
[sessionManager markInactive];
|
|
123
|
+
});
|
|
122
124
|
|
|
123
125
|
if (self.audioInterruptionsObserved) {
|
|
124
126
|
NSDictionary *body = @{@"type" : @"began", @"shouldResume" : @false};
|
|
@@ -134,7 +136,7 @@ static NSString *NotificationManagerContext = @"NotificationManagerContext";
|
|
|
134
136
|
NSDictionary *body = @{@"type" : @"ended", @"shouldResume" : @(shouldResume)};
|
|
135
137
|
[self.audioAPIModule invokeHandlerWithEventName:@"interruption" eventBody:body];
|
|
136
138
|
} else {
|
|
137
|
-
[audioEngine onInterruptionEnd:shouldResume];
|
|
139
|
+
dispatch_async(dispatch_get_main_queue(), ^{ [audioEngine onInterruptionEnd:shouldResume]; });
|
|
138
140
|
}
|
|
139
141
|
}
|
|
140
142
|
|
|
@@ -146,8 +148,10 @@ static NSString *NotificationManagerContext = @"NotificationManagerContext";
|
|
|
146
148
|
[notification.userInfo[AVAudioSessionSilenceSecondaryAudioHintTypeKey] integerValue];
|
|
147
149
|
|
|
148
150
|
if (secondaryAudioType == AVAudioSessionSilenceSecondaryAudioHintTypeBegin) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
152
|
+
[sessionManager markInactive];
|
|
153
|
+
[audioEngine onInterruptionBegin];
|
|
154
|
+
});
|
|
151
155
|
|
|
152
156
|
if (self.audioInterruptionsObserved) {
|
|
153
157
|
NSDictionary *body = @{@"type" : @"began", @"shouldResume" : @false};
|
|
@@ -162,7 +166,7 @@ static NSString *NotificationManagerContext = @"NotificationManagerContext";
|
|
|
162
166
|
NSDictionary *body = @{@"type" : @"ended", @"shouldResume" : @(shouldResume)};
|
|
163
167
|
[self.audioAPIModule invokeHandlerWithEventName:@"interruption" eventBody:body];
|
|
164
168
|
} else {
|
|
165
|
-
[audioEngine onInterruptionEnd:shouldResume];
|
|
169
|
+
dispatch_async(dispatch_get_main_queue(), ^{ [audioEngine onInterruptionEnd:shouldResume]; });
|
|
166
170
|
}
|
|
167
171
|
}
|
|
168
172
|
|
|
@@ -264,8 +268,10 @@ static NSString *NotificationManagerContext = @"NotificationManagerContext";
|
|
|
264
268
|
self.wasOtherAudioPlaying = shouldSilence;
|
|
265
269
|
|
|
266
270
|
if (shouldSilence) {
|
|
267
|
-
|
|
268
|
-
|
|
271
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
272
|
+
[sessionManager markInactive];
|
|
273
|
+
[audioEngine onInterruptionBegin];
|
|
274
|
+
});
|
|
269
275
|
NSDictionary *body = @{@"type" : @"began", @"shouldResume" : @false};
|
|
270
276
|
|
|
271
277
|
if (self.audioInterruptionsObserved) {
|
|
@@ -280,7 +286,7 @@ static NSString *NotificationManagerContext = @"NotificationManagerContext";
|
|
|
280
286
|
if (self.audioInterruptionsObserved) {
|
|
281
287
|
[self.audioAPIModule invokeHandlerWithEventName:@"interruption" eventBody:body];
|
|
282
288
|
} else {
|
|
283
|
-
[audioEngine onInterruptionEnd:true];
|
|
289
|
+
dispatch_async(dispatch_get_main_queue(), ^{ [audioEngine onInterruptionEnd:true]; });
|
|
284
290
|
}
|
|
285
291
|
}
|
|
286
292
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-audio-api",
|
|
3
|
-
"version": "0.11.0-nightly-
|
|
3
|
+
"version": "0.11.0-nightly-a2a703b-20251217",
|
|
4
4
|
"description": "react-native-audio-api provides system for controlling audio in React Native environment compatible with Web Audio API specification",
|
|
5
5
|
"bin": {
|
|
6
6
|
"setup-rn-audio-api-web": "./scripts/setup-rn-audio-api-web.js"
|