react-native-audio-api 0.11.0-nightly-bfab178-20251107 → 0.11.0-nightly-9f40b78-20251108

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.
@@ -17,12 +17,12 @@ AudioContextHostObject::AudioContextHostObject(
17
17
 
18
18
  JSI_HOST_FUNCTION_IMPL(AudioContextHostObject, close) {
19
19
  auto audioContext = std::static_pointer_cast<AudioContext>(context_);
20
- auto promise = promiseVendor_->createPromise(
21
- [audioContext](const std::shared_ptr<Promise> &promise) {
22
- audioContext->close();
23
-
24
- promise->resolve(
25
- [](jsi::Runtime &runtime) { return jsi::Value::undefined(); });
20
+ auto promise = promiseVendor_->createAsyncPromise(
21
+ [audioContext = std::move(audioContext)]() {
22
+ return [audioContext](jsi::Runtime &runtime) {
23
+ audioContext->close();
24
+ return jsi::Value::undefined();
25
+ };
26
26
  });
27
27
 
28
28
  return promise;
@@ -30,25 +30,20 @@ JSI_HOST_FUNCTION_IMPL(AudioContextHostObject, close) {
30
30
 
31
31
  JSI_HOST_FUNCTION_IMPL(AudioContextHostObject, resume) {
32
32
  auto audioContext = std::static_pointer_cast<AudioContext>(context_);
33
- auto promise = promiseVendor_->createPromise(
34
- [audioContext](const std::shared_ptr<Promise> &promise) {
33
+ auto promise = promiseVendor_->createAsyncPromise(
34
+ [audioContext = std::move(audioContext)]() {
35
35
  auto result = audioContext->resume();
36
-
37
- promise->resolve(
38
- [result](jsi::Runtime &runtime) { return jsi::Value(result); });
36
+ return [result](jsi::Runtime &runtime) { return jsi::Value(result); };
39
37
  });
40
-
41
38
  return promise;
42
39
  }
43
40
 
44
41
  JSI_HOST_FUNCTION_IMPL(AudioContextHostObject, suspend) {
45
42
  auto audioContext = std::static_pointer_cast<AudioContext>(context_);
46
- auto promise = promiseVendor_->createPromise(
47
- [audioContext](const std::shared_ptr<Promise> &promise) {
43
+ auto promise = promiseVendor_->createAsyncPromise(
44
+ [audioContext = std::move(audioContext)]() {
48
45
  auto result = audioContext->suspend();
49
-
50
- promise->resolve(
51
- [result](jsi::Runtime &runtime) { return jsi::Value(result); });
46
+ return [result](jsi::Runtime &runtime) { return jsi::Value(result); };
52
47
  });
53
48
 
54
49
  return promise;
@@ -17,49 +17,45 @@ OfflineAudioContextHostObject::OfflineAudioContextHostObject(
17
17
  }
18
18
 
19
19
  JSI_HOST_FUNCTION_IMPL(OfflineAudioContextHostObject, resume) {
20
- auto promise = promiseVendor_->createPromise(
21
- [this](const std::shared_ptr<Promise> &promise) {
22
- auto audioContext =
23
- std::static_pointer_cast<OfflineAudioContext>(context_);
24
- audioContext->resume();
25
- });
20
+ auto audioContext = std::static_pointer_cast<OfflineAudioContext>(context_);
21
+ auto promise = promiseVendor_->createAsyncPromise([audioContext]() {
22
+ audioContext->resume();
23
+ return [](jsi::Runtime &runtime) { return jsi::Value::undefined(); };
24
+ });
26
25
 
27
26
  return promise;
28
27
  }
29
28
 
30
29
  JSI_HOST_FUNCTION_IMPL(OfflineAudioContextHostObject, suspend) {
31
30
  double when = args[0].getNumber();
31
+ auto audioContext = std::static_pointer_cast<OfflineAudioContext>(context_);
32
32
 
33
- auto promise = promiseVendor_->createPromise(
34
- [this, when](const std::shared_ptr<Promise> &promise) {
35
- auto audioContext =
36
- std::static_pointer_cast<OfflineAudioContext>(context_);
37
- OfflineAudioContextSuspendCallback callback = [promise]() {
38
- promise->resolve(
39
- [](jsi::Runtime &runtime) { return jsi::Value::undefined(); });
40
- };
41
- audioContext->suspend(when, callback);
42
- });
33
+ auto promise = promiseVendor_->createAsyncPromise([=](Promise &&promise) {
34
+ OfflineAudioContextSuspendCallback callback = [promise =
35
+ std::move(promise)]() {
36
+ promise.resolve(
37
+ [](jsi::Runtime &runtime) { return jsi::Value::undefined(); });
38
+ };
39
+ audioContext->suspend(when, callback);
40
+ });
43
41
 
44
42
  return promise;
45
43
  }
46
44
 
47
45
  JSI_HOST_FUNCTION_IMPL(OfflineAudioContextHostObject, startRendering) {
48
- auto promise = promiseVendor_->createPromise(
49
- [this](const std::shared_ptr<Promise> &promise) {
50
- auto audioContext =
51
- std::static_pointer_cast<OfflineAudioContext>(context_);
52
-
46
+ auto audioContext = std::static_pointer_cast<OfflineAudioContext>(context_);
47
+ auto promise =
48
+ promiseVendor_->createAsyncPromise([audioContext](Promise &&promise) {
53
49
  OfflineAudioContextResultCallback callback =
54
- [promise](const std::shared_ptr<AudioBuffer> &audioBuffer) -> void {
55
- auto audioBufferHostObject =
56
- std::make_shared<AudioBufferHostObject>(audioBuffer);
57
- promise->resolve([audioBufferHostObject = std::move(
58
- audioBufferHostObject)](jsi::Runtime &runtime) {
59
- return jsi::Object::createFromHostObject(
60
- runtime, audioBufferHostObject);
61
- });
62
- };
50
+ [promise = std::move(promise)](
51
+ const std::shared_ptr<AudioBuffer> &audioBuffer) {
52
+ auto audioBufferHostObject =
53
+ std::make_shared<AudioBufferHostObject>(audioBuffer);
54
+ promise.resolve([audioBufferHostObject](jsi::Runtime &runtime) {
55
+ return jsi::Object::createFromHostObject(
56
+ runtime, audioBufferHostObject);
57
+ });
58
+ };
63
59
 
64
60
  audioContext->startRendering(callback);
65
61
  });
@@ -24,32 +24,21 @@ JSI_HOST_FUNCTION_IMPL(AudioStretcherHostObject, changePlaybackSpeed) {
24
24
  args[0].getObject(runtime).asHostObject<AudioBufferHostObject>(runtime);
25
25
  auto playbackSpeed = static_cast<float>(args[1].asNumber());
26
26
 
27
- auto promise = promiseVendor_->createPromise(
28
- [audioBuffer, playbackSpeed](std::shared_ptr<Promise> promise) {
29
- std::thread([audioBuffer,
30
- playbackSpeed,
31
- promise = std::move(promise)]() {
32
- auto result = AudioStretcher::changePlaybackSpeed(
33
- *audioBuffer->audioBuffer_, playbackSpeed);
34
-
35
- if (!result) {
36
- promise->reject("Failed to change audio playback speed.");
37
- return;
38
- }
39
-
40
- auto audioBufferHostObject =
41
- std::make_shared<AudioBufferHostObject>(result);
42
-
43
- promise->resolve([audioBufferHostObject = std::move(
44
- audioBufferHostObject)](jsi::Runtime &runtime) {
45
- auto jsiObject = jsi::Object::createFromHostObject(
46
- runtime, audioBufferHostObject);
47
- jsiObject.setExternalMemoryPressure(
48
- runtime, audioBufferHostObject->getSizeInBytes());
49
- return jsiObject;
50
- });
51
- }).detach();
52
- });
27
+ auto promise = promiseVendor_->createAsyncPromise([=]() -> PromiseResolver {
28
+ auto result = AudioStretcher::changePlaybackSpeed(
29
+ *audioBuffer->audioBuffer_, playbackSpeed);
30
+
31
+ if (result == nullptr) {
32
+ return [](jsi::Runtime &runtime) {
33
+ return std::string("Failed to change audio playback speed.");
34
+ };
35
+ }
36
+ return [result](jsi::Runtime &runtime) {
37
+ auto audioBufferHostObject =
38
+ std::make_shared<AudioBufferHostObject>(result);
39
+ return jsi::Object::createFromHostObject(runtime, audioBufferHostObject);
40
+ };
41
+ });
53
42
  return promise;
54
43
  }
55
44
 
@@ -31,6 +31,12 @@ void AudioBufferQueueSourceNode::stop(double when) {
31
31
  isPaused_ = false;
32
32
  }
33
33
 
34
+ void AudioBufferQueueSourceNode::start(double when) {
35
+ isPaused_ = false;
36
+ stopTime_ = -1.0;
37
+ AudioScheduledSourceNode::start(when);
38
+ }
39
+
34
40
  void AudioBufferQueueSourceNode::pause() {
35
41
  AudioScheduledSourceNode::stop(0.0);
36
42
  isPaused_ = true;
@@ -79,6 +85,7 @@ void AudioBufferQueueSourceNode::disable() {
79
85
  playbackState_ = PlaybackState::UNSCHEDULED;
80
86
  startTime_ = -1.0;
81
87
  stopTime_ = -1.0;
88
+ isPaused_ = false;
82
89
 
83
90
  return;
84
91
  }
@@ -21,6 +21,7 @@ class AudioBufferQueueSourceNode : public AudioBufferBaseSourceNode {
21
21
  ~AudioBufferQueueSourceNode() override;
22
22
 
23
23
  void stop(double when) override;
24
+ void start(double when) override;
24
25
  void pause();
25
26
 
26
27
  std::string enqueueBuffer(const std::shared_ptr<AudioBuffer> &buffer);
@@ -78,7 +78,6 @@ void AudioScheduledSourceNode::updatePlaybackInfo(
78
78
  size_t stopFrame = stopTime_ == -1.0
79
79
  ? std::numeric_limits<size_t>::max()
80
80
  : dsp::timeToSampleFrame(stopTime_, sampleRate);
81
-
82
81
  if (isFinished()) {
83
82
  startOffset = 0;
84
83
  nonSilentFramesToProcess = 0;
@@ -28,7 +28,7 @@ class AudioScheduledSourceNode : public AudioNode {
28
28
  enum class PlaybackState { UNSCHEDULED, SCHEDULED, PLAYING, STOP_SCHEDULED, FINISHED };
29
29
  explicit AudioScheduledSourceNode(BaseAudioContext *context);
30
30
 
31
- void start(double when);
31
+ virtual void start(double when);
32
32
  virtual void stop(double when);
33
33
 
34
34
  bool isUnscheduled();
@@ -5,62 +5,6 @@ namespace audioapi {
5
5
 
6
6
  using namespace facebook;
7
7
 
8
- jsi::Value PromiseVendor::createPromise(
9
- const std::function<void(std::shared_ptr<Promise>)> &function) {
10
- if (runtime_ == nullptr) {
11
- throw std::runtime_error("Runtime was null!");
12
- }
13
-
14
- auto &runtime = *runtime_;
15
- auto callInvoker = callInvoker_;
16
-
17
- // get Promise constructor
18
- auto promiseCtor = runtime.global().getPropertyAsFunction(runtime, "Promise");
19
-
20
- // create a "run" function (first Promise arg)
21
- auto runPromise = jsi::Function::createFromHostFunction(
22
- runtime,
23
- jsi::PropNameID::forUtf8(runtime, "runPromise"),
24
- 2,
25
- [callInvoker, function](
26
- jsi::Runtime &runtime,
27
- const jsi::Value &thisValue,
28
- const jsi::Value *arguments,
29
- size_t count) -> jsi::Value {
30
- auto resolveLocal = arguments[0].asObject(runtime).asFunction(runtime);
31
- auto resolve = std::make_shared<jsi::Function>(std::move(resolveLocal));
32
- auto rejectLocal = arguments[1].asObject(runtime).asFunction(runtime);
33
- auto reject = std::make_shared<jsi::Function>(std::move(rejectLocal));
34
-
35
- auto resolveWrapper =
36
- [resolve, &runtime, callInvoker](
37
- const std::function<jsi::Value(jsi::Runtime &)> &resolver)
38
- -> void {
39
- callInvoker->invokeAsync([resolve, &runtime, resolver]() -> void {
40
- auto valueShared = std::make_shared<jsi::Value>(resolver(runtime));
41
-
42
- resolve->call(runtime, *valueShared);
43
- });
44
- };
45
-
46
- auto rejectWrapper = [reject, &runtime, callInvoker](
47
- const std::string &errorMessage) -> void {
48
- callInvoker->invokeAsync([reject, &runtime, errorMessage]() -> void {
49
- auto error = jsi::JSError(runtime, errorMessage);
50
- reject->call(runtime, error.value());
51
- });
52
- };
53
-
54
- auto promise = std::make_shared<Promise>(resolveWrapper, rejectWrapper);
55
- function(promise);
56
-
57
- return jsi::Value::undefined();
58
- });
59
-
60
- // return new Promise((resolve, reject) => ...)
61
- return promiseCtor.callAsConstructor(runtime, runPromise);
62
- }
63
-
64
8
  jsi::Value PromiseVendor::createAsyncPromise(
65
9
  std::function<PromiseResolver()> &&function) {
66
10
  auto &runtime = *runtime_;
@@ -95,6 +39,39 @@ jsi::Value PromiseVendor::createAsyncPromise(
95
39
  return promiseCtor.callAsConstructor(runtime, std::move(promiseFunction));
96
40
  }
97
41
 
42
+ jsi::Value PromiseVendor::createAsyncPromise(
43
+ std::function<void(Promise &&)> &&function) {
44
+ auto &runtime = *runtime_;
45
+ auto callInvoker = callInvoker_;
46
+ auto threadPool = threadPool_;
47
+ auto promiseCtor = runtime.global().getPropertyAsFunction(runtime, "Promise");
48
+ auto promiseLambda = [threadPool = std::move(threadPool),
49
+ callInvoker = std::move(callInvoker),
50
+ function = std::move(function)](
51
+ jsi::Runtime &runtime,
52
+ const jsi::Value &thisValue,
53
+ const jsi::Value *arguments,
54
+ size_t count) mutable -> jsi::Value {
55
+ auto resolveLocal = arguments[0].asObject(runtime).asFunction(runtime);
56
+ auto rejectLocal = arguments[1].asObject(runtime).asFunction(runtime);
57
+
58
+ Promise promise(
59
+ std::move(callInvoker),
60
+ std::move(resolveLocal),
61
+ std::move(rejectLocal));
62
+
63
+ threadPool->schedule(std::move(function), std::move(promise));
64
+
65
+ return jsi::Value::undefined();
66
+ };
67
+ auto promiseFunction = jsi::Function::createFromHostFunction(
68
+ runtime,
69
+ jsi::PropNameID::forUtf8(runtime, "asyncPromise"),
70
+ 2,
71
+ std::move(promiseLambda));
72
+ return promiseCtor.callAsConstructor(runtime, std::move(promiseFunction));
73
+ }
74
+
98
75
  void PromiseVendor::asyncPromiseJob(
99
76
  std::shared_ptr<react::CallInvoker> callInvoker,
100
77
  std::function<PromiseResolver()> &&function,
@@ -17,20 +17,45 @@ namespace audioapi {
17
17
  using namespace facebook;
18
18
 
19
19
  class Promise {
20
+ struct Inner {
21
+ std::shared_ptr<react::CallInvoker> callInvoker;
22
+ jsi::Function resolve;
23
+ jsi::Function reject;
24
+ };
25
+
20
26
  public:
21
- Promise(std::function<void(const std::function<jsi::Value(jsi::Runtime&)>)> resolve, std::function<void(const std::string &)> reject) : resolve_(std::move(resolve)), reject_(std::move(reject)) {}
27
+ explicit Promise(std::shared_ptr<react::CallInvoker> &&callInvoker, jsi::Function &&resolve, jsi::Function &&reject):
28
+ inner_(std::make_shared<Inner>(Inner{std::move(callInvoker), std::move(resolve), std::move(reject)})) {}
29
+
30
+ Promise(const Promise &other) {
31
+ inner_ = other.inner_;
32
+ }
33
+ Promise(Promise &&other) noexcept : inner_(std::move(other.inner_)) {}
34
+ Promise& operator=(Promise &&other) noexcept {
35
+ if (this != &other) {
36
+ inner_ = std::move(other.inner_);
37
+ }
38
+ return *this;
39
+ }
22
40
 
23
- void resolve(const std::function<jsi::Value(jsi::Runtime&)> &resolver) {
24
- resolve_(std::forward<const std::function<jsi::Value(jsi::Runtime&)>>(resolver));
25
- }
41
+ void resolve(const std::function<jsi::Value(jsi::Runtime&)> &&resolver) const {
42
+ auto inner = inner_;
43
+ inner->callInvoker->invokeAsync([inner = std::move(inner), resolver = std::forward<decltype(resolver)>(resolver)](jsi::Runtime &runtime) -> void {
44
+ auto valueShared = std::make_shared<jsi::Value>(resolver(runtime));
45
+ inner->resolve.call(runtime, *valueShared);
46
+ });
47
+ }
26
48
 
27
- void reject(const std::string &errorMessage) {
28
- reject_(errorMessage);
29
- }
49
+ void reject(const std::string &errorMessage) const {
50
+ auto inner = inner_;
51
+ inner->callInvoker->invokeAsync([inner = std::move(inner), errorMessage](jsi::Runtime &runtime) -> void {
52
+ auto error = jsi::JSError(runtime, errorMessage);
53
+ inner->reject.call(runtime, error.value());
54
+ });
55
+ }
30
56
 
31
57
  private:
32
- std::function<void(const std::function<jsi::Value(jsi::Runtime&)>)> resolve_;
33
- std::function<void(const std::string &)> reject_;
58
+ std::shared_ptr<Inner> inner_;
34
59
  };
35
60
 
36
61
  using PromiseResolver = std::function<std::variant<jsi::Value, std::string>(jsi::Runtime&)>;
@@ -43,8 +68,6 @@ class PromiseVendor {
43
68
  audioapi::PROMISE_VENDOR_THREAD_POOL_LOAD_BALANCER_QUEUE_SIZE,
44
69
  audioapi::PROMISE_VENDOR_THREAD_POOL_WORKER_QUEUE_SIZE)) {}
45
70
 
46
- jsi::Value createPromise(const std::function<void(std::shared_ptr<Promise>)> &function);
47
-
48
71
  /// @brief Creates an asynchronous promise.
49
72
  /// @param function The function to execute asynchronously. It should return either a jsi::Value on success or a std::string error message on failure.
50
73
  /// @return The created promise.
@@ -66,6 +89,13 @@ class PromiseVendor {
66
89
  /// return promise;
67
90
  jsi::Value createAsyncPromise(std::function<PromiseResolver()> &&function);
68
91
 
92
+ /// @brief Creates an asynchronous promise.
93
+ /// @param function The function to execute asynchronously. It receives a Promise object to resolve or reject the promise.
94
+ /// @return The created promise.
95
+ /// @note The function is executed on a different thread, the promise should be resolved or rejected using the provided Promise object.
96
+ /// @note IMPORTANT: This function is not thread-safe and should be called from a single thread only. (comes from underlying ThreadPool implementation)
97
+ jsi::Value createAsyncPromise(std::function<void(Promise&&)> &&function);
98
+
69
99
  private:
70
100
  jsi::Runtime *runtime_;
71
101
  std::shared_ptr<react::CallInvoker> callInvoker_;
@@ -118,15 +118,16 @@ RCT_EXPORT_METHOD(
118
118
  setAudioSessionActivity : (BOOL)enabled resolve : (RCTPromiseResolveBlock)resolve reject : (RCTPromiseRejectBlock)
119
119
  reject)
120
120
  {
121
- if (!self.audioSessionManager.shouldManageSession) {
122
- [self.audioSessionManager setShouldManageSession:true];
123
- }
124
- if ([self.audioSessionManager setActive:enabled]) {
125
- resolve(@"true");
126
- return;
127
- }
128
-
129
- resolve(@"false");
121
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
122
+ if (!self.audioSessionManager.shouldManageSession) {
123
+ [self.audioSessionManager setShouldManageSession:true];
124
+ }
125
+ if ([self.audioSessionManager setActive:enabled]) {
126
+ resolve(@"true");
127
+ return;
128
+ }
129
+ resolve(@"false");
130
+ });
130
131
  }
131
132
 
132
133
  RCT_EXPORT_METHOD(
@@ -173,19 +174,25 @@ RCT_EXPORT_METHOD(
173
174
  requestRecordingPermissions : (nonnull RCTPromiseResolveBlock)resolve reject : (nonnull RCTPromiseRejectBlock)
174
175
  reject)
175
176
  {
176
- [self.audioSessionManager requestRecordingPermissions:resolve reject:reject];
177
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
178
+ [self.audioSessionManager requestRecordingPermissions:resolve reject:reject];
179
+ });
177
180
  }
178
181
 
179
182
  RCT_EXPORT_METHOD(
180
183
  checkRecordingPermissions : (nonnull RCTPromiseResolveBlock)resolve reject : (nonnull RCTPromiseRejectBlock)reject)
181
184
  {
182
- [self.audioSessionManager checkRecordingPermissions:resolve reject:reject];
185
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
186
+ [self.audioSessionManager checkRecordingPermissions:resolve reject:reject];
187
+ });
183
188
  }
184
189
 
185
190
  RCT_EXPORT_METHOD(
186
191
  getDevicesInfo : (nonnull RCTPromiseResolveBlock)resolve reject : (nonnull RCTPromiseRejectBlock)reject)
187
192
  {
188
- [self.audioSessionManager getDevicesInfo:resolve reject:reject];
193
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
194
+ [self.audioSessionManager getDevicesInfo:resolve reject:reject];
195
+ });
189
196
  }
190
197
 
191
198
  RCT_EXPORT_METHOD(disableSessionManagement)
@@ -233,4 +240,9 @@ RCT_EXPORT_METHOD(disableSessionManagement)
233
240
  }
234
241
  }
235
242
 
243
+ - (dispatch_queue_t)methodQueue
244
+ {
245
+ return dispatch_queue_create("swmansion.audioapi.Queue", DISPATCH_QUEUE_SERIAL);
246
+ }
247
+
236
248
  @end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-audio-api",
3
- "version": "0.11.0-nightly-bfab178-20251107",
3
+ "version": "0.11.0-nightly-9f40b78-20251108",
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"