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.
@@ -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>::Ok(std::format("file://{}", filePath_));
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
- 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 setLockScreenInfo(ReadableMap info);
60
-
61
- @ReactMethod
62
- @DoNotStrip
63
- public abstract void resetLockScreenInfo();
64
-
65
- @ReactMethod
66
- @DoNotStrip
67
- public abstract void enableRemoteCommand(String name, boolean enabled);
68
-
69
- @ReactMethod
70
- @DoNotStrip
71
- public abstract void observeAudioInterruptions(boolean enabled);
72
-
73
- @ReactMethod
74
- @DoNotStrip
75
- public abstract void activelyReclaimSession(boolean enabled);
76
-
77
- @ReactMethod
78
- @DoNotStrip
79
- public abstract void observeVolumeChanges(boolean enabled);
80
-
81
- @ReactMethod
82
- @DoNotStrip
83
- public abstract void requestRecordingPermissions(Promise promise);
84
-
85
- @ReactMethod
86
- @DoNotStrip
87
- public abstract void checkRecordingPermissions(Promise promise);
88
-
89
- @ReactMethod
90
- @DoNotStrip
91
- public abstract void getDevicesInfo(Promise promise);
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("Already recording");
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("Not recording");
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)
@@ -6,6 +6,8 @@ typedef struct objc_object NSURL;
6
6
  typedef struct objc_object AudioBufferList;
7
7
  #endif // __OBJC__
8
8
 
9
+ #include <memory>
10
+
9
11
  namespace audioapi {
10
12
 
11
13
  class AudioFileProperties;
@@ -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
- [audioEngine onInterruptionBegin];
121
- [sessionManager markInactive];
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
- [sessionManager markInactive];
150
- [audioEngine onInterruptionBegin];
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
- [sessionManager markInactive];
268
- [audioEngine onInterruptionBegin];
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-52d0b79-20251216",
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"