react-native-audio-api 0.10.0-nightly-44925d7-20251105 β†’ 0.10.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.
package/README.md CHANGED
@@ -19,19 +19,8 @@ check out the [Getting Started](https://docs.swmansion.com/react-native-audio-ap
19
19
 
20
20
  ### Planned
21
21
 
22
- ### <img src="https://img.shields.io/badge/Coming_in-0.9.0-orange" />
23
-
24
- - **JS Audio Worklets V1 🐎**<br />
25
- Receive events and data callbacks from audio thread to synchronize with UI on UI thread.
26
-
27
22
  ### <img src="https://img.shields.io/badge/Coming_in-x.x.x-orange" />
28
23
 
29
- - **Convolver Node 🐐**<br />
30
- Realistic reverb and spatial effects in the browser by applying impulse responses. It makes audio sound like it’s being played in real spaces, from small rooms to cathedrals, or through hardware like amps and speakers
31
-
32
- - **Decoding and utility modules πŸ”§**<br />
33
- Decode and modify audio data without the need to create AudioContext first through a set of utility classes
34
-
35
24
  - **DynamicCompressorNode 〽️**<br />
36
25
  Reduce the volume of loud sounds and boost quieter nodes to balance the audio signal, avoid clipping or distorted sounds
37
26
 
@@ -47,9 +36,22 @@ check out the [Getting Started](https://docs.swmansion.com/react-native-audio-ap
47
36
  - **Noise Cancellation πŸ¦‡**<br />
48
37
  System-based active noise and echo cancellation support
49
38
 
39
+ ### <a href="https://github.com/software-mansion/react-native-audio-api/releases/tag/0.10.0"><img src="https://img.shields.io/badge/Released_in-0.10.0-green" /></a>
40
+
41
+ - **Decoding and utility modules πŸ”§**<br />
42
+ Decode and modify audio data without the need to create AudioContext first through a set of utility classes
43
+
44
+ - **Convolver Node 🐐**<br />
45
+ Realistic reverb and spatial effects in the browser by applying impulse responses. It makes audio sound like it’s being played in real spaces, from small rooms to cathedrals, or through hardware like amps and speakers
46
+
50
47
  - **JS Audio Worklets V2 🐎**<br />
51
48
  Customize the process pipeline with JS functions running on audio thread.
52
49
 
50
+ ### <a href="https://github.com/software-mansion/react-native-audio-api/releases/tag/0.9.0"><img src="https://img.shields.io/badge/Released_in-0.9.0-green" /></a>
51
+
52
+ - **JS Audio Worklets V1 🐎**<br />
53
+ Receive events and data callbacks from audio thread to synchronize with UI on UI thread.
54
+
53
55
  ### <a href="https://github.com/software-mansion/react-native-audio-api/releases/tag/0.8.0"><img src="https://img.shields.io/badge/Released_in-0.8.0-green" /></a>
54
56
 
55
57
  - **Decoding support for m4a/mp4/aac/ogg/opus πŸ“** <br />
@@ -2,7 +2,6 @@ package com.swmansion.audioapi
2
2
 
3
3
  import com.facebook.jni.HybridData
4
4
  import com.facebook.react.bridge.LifecycleEventListener
5
- import com.facebook.react.bridge.NativeModule
6
5
  import com.facebook.react.bridge.Promise
7
6
  import com.facebook.react.bridge.ReactApplicationContext
8
7
  import com.facebook.react.bridge.ReadableArray
@@ -27,7 +26,6 @@ class AudioAPIModule(
27
26
  val reactContext: WeakReference<ReactApplicationContext> = WeakReference(reactContext)
28
27
 
29
28
  private val mHybridData: HybridData
30
- private var reanimatedModule: NativeModule? = null
31
29
 
32
30
  external fun initHybrid(
33
31
  workletsModule: Any?,
@@ -28,7 +28,7 @@ AudioBufferBaseSourceNodeHostObject::~AudioBufferBaseSourceNodeHostObject() {
28
28
  // When JSI object is garbage collected (together with the eventual callback),
29
29
  // underlying source node might still be active and try to call the
30
30
  // non-existing callback.
31
- sourceNode->clearOnPositionChangedCallback();
31
+ sourceNode->setOnPositionChangedCallbackId(0);
32
32
  }
33
33
 
34
34
  JSI_PROPERTY_GETTER_IMPL(AudioBufferBaseSourceNodeHostObject, detune) {
@@ -37,7 +37,7 @@ AudioBufferSourceNodeHostObject::~AudioBufferSourceNodeHostObject() {
37
37
  // When JSI object is garbage collected (together with the eventual callback),
38
38
  // underlying source node might still be active and try to call the
39
39
  // non-existing callback.
40
- audioBufferSourceNode->clearOnLoopEndedCallback();
40
+ audioBufferSourceNode->setOnLoopEndedCallbackId(0);
41
41
  }
42
42
 
43
43
  JSI_PROPERTY_GETTER_IMPL(AudioBufferSourceNodeHostObject, loop) {
@@ -22,7 +22,7 @@ AudioScheduledSourceNodeHostObject::~AudioScheduledSourceNodeHostObject() {
22
22
  // When JSI object is garbage collected (together with the eventual callback),
23
23
  // underlying source node might still be active and try to call the
24
24
  // non-existing callback.
25
- audioScheduledSourceNode->clearOnEndedCallback();
25
+ audioScheduledSourceNode->setOnEndedCallbackId(0);
26
26
  }
27
27
 
28
28
  JSI_PROPERTY_SETTER_IMPL(AudioScheduledSourceNodeHostObject, onEnded) {
@@ -11,16 +11,16 @@
11
11
  namespace audioapi {
12
12
  ConvolverNode::ConvolverNode(
13
13
  BaseAudioContext *context,
14
- std::shared_ptr<AudioBuffer> buffer,
14
+ const std::shared_ptr<AudioBuffer> &buffer,
15
15
  bool disableNormalization)
16
16
  : AudioNode(context),
17
- buffer_(nullptr),
18
- internalBuffer_(nullptr),
19
- signalledToStop_(false),
20
17
  remainingSegments_(0),
21
18
  internalBufferIndex_(0),
19
+ signalledToStop_(false),
22
20
  scaleFactor_(1.0f),
23
- intermediateBus_(nullptr) {
21
+ intermediateBus_(nullptr),
22
+ buffer_(nullptr),
23
+ internalBuffer_(nullptr) {
24
24
  channelCount_ = 2;
25
25
  channelCountMode_ = ChannelCountMode::CLAMPED_MAX;
26
26
  normalize_ = !disableNormalization;
@@ -19,7 +19,7 @@ class AudioBuffer;
19
19
 
20
20
  class ConvolverNode : public AudioNode {
21
21
  public:
22
- explicit ConvolverNode(BaseAudioContext *context, std::shared_ptr<AudioBuffer> buffer, bool disableNormalization);
22
+ explicit ConvolverNode(BaseAudioContext *context, const std::shared_ptr<AudioBuffer>& buffer, bool disableNormalization);
23
23
 
24
24
  [[nodiscard]] bool getNormalize_() const;
25
25
  [[nodiscard]] const std::shared_ptr<AudioBuffer> &getBuffer() const;
@@ -36,20 +36,15 @@ std::shared_ptr<AudioParam> AudioBufferBaseSourceNode::getPlaybackRateParam()
36
36
  return playbackRateParam_;
37
37
  }
38
38
 
39
- void AudioBufferBaseSourceNode::clearOnPositionChangedCallback() {
40
- if (onPositionChangedCallbackId_ == 0 || context_ == nullptr ||
41
- context_->audioEventHandlerRegistry_ == nullptr) {
42
- return;
43
- }
44
-
45
- context_->audioEventHandlerRegistry_->unregisterHandler(
46
- "positionChanged", onPositionChangedCallbackId_);
47
- onPositionChangedCallbackId_ = 0;
48
- }
49
-
50
39
  void AudioBufferBaseSourceNode::setOnPositionChangedCallbackId(
51
40
  uint64_t callbackId) {
52
- onPositionChangedCallbackId_ = callbackId;
41
+ auto oldCallbackId = onPositionChangedCallbackId_.exchange(
42
+ callbackId, std::memory_order_acq_rel);
43
+
44
+ if (oldCallbackId != 0) {
45
+ audioEventHandlerRegistry_->unregisterHandler(
46
+ "positionChanged", oldCallbackId);
47
+ }
53
48
  }
54
49
 
55
50
  void AudioBufferBaseSourceNode::setOnPositionChangedInterval(int interval) {
@@ -66,14 +61,16 @@ std::mutex &AudioBufferBaseSourceNode::getBufferLock() {
66
61
  }
67
62
 
68
63
  void AudioBufferBaseSourceNode::sendOnPositionChangedEvent() {
69
- if (onPositionChangedCallbackId_ != 0 &&
70
- onPositionChangedTime_ > onPositionChangedInterval_ &&
71
- context_->audioEventHandlerRegistry_ != nullptr) {
64
+ auto onPositionChangedCallbackId =
65
+ onPositionChangedCallbackId_.load(std::memory_order_acquire);
66
+
67
+ if (onPositionChangedCallbackId != 0 &&
68
+ onPositionChangedTime_ > onPositionChangedInterval_) {
72
69
  std::unordered_map<std::string, EventValue> body = {
73
70
  {"value", getCurrentPosition()}};
74
71
 
75
- context_->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
76
- "positionChanged", onPositionChangedCallbackId_, body);
72
+ audioEventHandlerRegistry_->invokeHandlerWithEventBody(
73
+ "positionChanged", onPositionChangedCallbackId, body);
77
74
 
78
75
  onPositionChangedTime_ = 0;
79
76
  }
@@ -19,7 +19,6 @@ class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
19
19
  [[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
20
20
  [[nodiscard]] std::shared_ptr<AudioParam> getPlaybackRateParam() const;
21
21
 
22
- void clearOnPositionChangedCallback();
23
22
  void setOnPositionChangedCallbackId(uint64_t callbackId);
24
23
  void setOnPositionChangedInterval(int interval);
25
24
  [[nodiscard]] int getOnPositionChangedInterval() const;
@@ -123,19 +123,13 @@ void AudioBufferSourceNode::disable() {
123
123
  alignedBus_.reset();
124
124
  }
125
125
 
126
- void AudioBufferSourceNode::clearOnLoopEndedCallback() {
127
- if (onLoopEndedCallbackId_ == 0 || context_ == nullptr ||
128
- context_->audioEventHandlerRegistry_ == nullptr) {
129
- return;
130
- }
131
-
132
- context_->audioEventHandlerRegistry_->unregisterHandler(
133
- "loopEnded", onLoopEndedCallbackId_);
134
- onLoopEndedCallbackId_ = 0;
135
- }
136
-
137
126
  void AudioBufferSourceNode::setOnLoopEndedCallbackId(uint64_t callbackId) {
138
- onLoopEndedCallbackId_ = callbackId;
127
+ auto oldCallbackId =
128
+ onLoopEndedCallbackId_.exchange(callbackId, std::memory_order_acq_rel);
129
+
130
+ if (oldCallbackId != 0) {
131
+ audioEventHandlerRegistry_->unregisterHandler("loopEnded", oldCallbackId);
132
+ }
139
133
  }
140
134
 
141
135
  std::shared_ptr<AudioBus> AudioBufferSourceNode::processNode(
@@ -171,8 +165,8 @@ void AudioBufferSourceNode::sendOnLoopEndedEvent() {
171
165
  auto onLoopEndedCallbackId =
172
166
  onLoopEndedCallbackId_.load(std::memory_order_acquire);
173
167
  if (onLoopEndedCallbackId != 0) {
174
- context_->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
175
- "loopEnded", onLoopEndedCallbackId_, {});
168
+ audioEventHandlerRegistry_->invokeHandlerWithEventBody(
169
+ "loopEnded", onLoopEndedCallbackId, {});
176
170
  }
177
171
  }
178
172
 
@@ -34,7 +34,6 @@ class AudioBufferSourceNode : public AudioBufferBaseSourceNode {
34
34
  void start(double when, double offset, double duration = -1);
35
35
  void disable() override;
36
36
 
37
- void clearOnLoopEndedCallback();
38
37
  void setOnLoopEndedCallbackId(uint64_t callbackId);
39
38
 
40
39
  protected:
@@ -14,6 +14,7 @@ AudioScheduledSourceNode::AudioScheduledSourceNode(BaseAudioContext *context)
14
14
  stopTime_(-1.0),
15
15
  playbackState_(PlaybackState::UNSCHEDULED) {
16
16
  numberOfInputs_ = 0;
17
+ audioEventHandlerRegistry_ = context_->audioEventHandlerRegistry_;
17
18
  }
18
19
 
19
20
  void AudioScheduledSourceNode::start(double when) {
@@ -45,19 +46,13 @@ bool AudioScheduledSourceNode::isStopScheduled() {
45
46
  return playbackState_ == PlaybackState::STOP_SCHEDULED;
46
47
  }
47
48
 
48
- void AudioScheduledSourceNode::clearOnEndedCallback() {
49
- if (onEndedCallbackId_ == 0 || context_ == nullptr ||
50
- context_->audioEventHandlerRegistry_ == nullptr) {
51
- return;
52
- }
53
-
54
- context_->audioEventHandlerRegistry_->unregisterHandler(
55
- "ended", onEndedCallbackId_);
56
- onEndedCallbackId_ = 0;
57
- }
58
-
59
49
  void AudioScheduledSourceNode::setOnEndedCallbackId(const uint64_t callbackId) {
60
- onEndedCallbackId_ = callbackId;
50
+ auto oldCallbackId =
51
+ onEndedCallbackId_.exchange(callbackId, std::memory_order_acq_rel);
52
+
53
+ if (oldCallbackId != 0) {
54
+ audioEventHandlerRegistry_->unregisterHandler("ended", oldCallbackId);
55
+ }
61
56
  }
62
57
 
63
58
  void AudioScheduledSourceNode::updatePlaybackInfo(
@@ -160,9 +155,10 @@ void AudioScheduledSourceNode::updatePlaybackInfo(
160
155
  void AudioScheduledSourceNode::disable() {
161
156
  AudioNode::disable();
162
157
 
163
- if (context_->audioEventHandlerRegistry_ != nullptr) {
164
- context_->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
165
- "ended", onEndedCallbackId_, {});
158
+ auto onEndedCallbackId = onEndedCallbackId_.load(std::memory_order_acquire);
159
+ if (onEndedCallbackId != 0) {
160
+ audioEventHandlerRegistry_->invokeHandlerWithEventBody(
161
+ "ended", onEndedCallbackId, {});
166
162
  }
167
163
  }
168
164
 
@@ -16,7 +16,7 @@
16
16
 
17
17
  namespace audioapi {
18
18
 
19
- class AudioEventHandlerRegistry;
19
+ class IAudioEventHandlerRegistry;
20
20
 
21
21
  class AudioScheduledSourceNode : public AudioNode {
22
22
  public:
@@ -37,7 +37,6 @@ class AudioScheduledSourceNode : public AudioNode {
37
37
  bool isFinished();
38
38
  bool isStopScheduled();
39
39
 
40
- void clearOnEndedCallback();
41
40
  void setOnEndedCallbackId(uint64_t callbackId);
42
41
 
43
42
  void disable() override;
@@ -49,6 +48,7 @@ class AudioScheduledSourceNode : public AudioNode {
49
48
  PlaybackState playbackState_;
50
49
 
51
50
  std::atomic<uint64_t> onEndedCallbackId_ = 0;
51
+ std::shared_ptr<IAudioEventHandlerRegistry> audioEventHandlerRegistry_;
52
52
 
53
53
  void updatePlaybackInfo(
54
54
  const std::shared_ptr<AudioBus>& processingBus,
@@ -25,10 +25,10 @@ StreamerNode::StreamerNode(BaseAudioContext *context)
25
25
  codecpar_(nullptr),
26
26
  pkt_(nullptr),
27
27
  frame_(nullptr),
28
- bufferedBus_(nullptr),
29
- audio_stream_index_(-1),
30
28
  swrCtx_(nullptr),
31
29
  resampledData_(nullptr),
30
+ bufferedBus_(nullptr),
31
+ audio_stream_index_(-1),
32
32
  maxResampledSamples_(0),
33
33
  processedSamples_(0) {}
34
34
 
@@ -4,7 +4,7 @@ namespace audioapi {
4
4
 
5
5
  WorkletsRunner::WorkletsRunner(
6
6
  std::weak_ptr<worklets::WorkletRuntime> weakRuntime,
7
- std::shared_ptr<worklets::SerializableWorklet> shareableWorklet,
7
+ const std::shared_ptr<worklets::SerializableWorklet> &shareableWorklet,
8
8
  bool shouldLockRuntime)
9
9
  : weakRuntime_(std::move(weakRuntime)),
10
10
  shouldLockRuntime(shouldLockRuntime) {
@@ -33,8 +33,8 @@ WorkletsRunner::WorkletsRunner(
33
33
  WorkletsRunner::WorkletsRunner(WorkletsRunner &&other)
34
34
  : weakRuntime_(std::move(other.weakRuntime_)),
35
35
  unsafeRuntimePtr(other.unsafeRuntimePtr),
36
- shouldLockRuntime(other.shouldLockRuntime),
37
- workletInitialized(other.workletInitialized) {
36
+ workletInitialized(other.workletInitialized),
37
+ shouldLockRuntime(other.shouldLockRuntime) {
38
38
  if (workletInitialized) {
39
39
  std::memcpy(&unsafeWorklet, &other.unsafeWorklet, sizeof(unsafeWorklet));
40
40
  other.workletInitialized = false;
@@ -28,7 +28,7 @@ class WorkletsRunner {
28
28
  public:
29
29
  explicit WorkletsRunner(
30
30
  std::weak_ptr<worklets::WorkletRuntime> weakRuntime,
31
- std::shared_ptr<worklets::SerializableWorklet> shareableWorklet,
31
+ const std::shared_ptr<worklets::SerializableWorklet>& shareableWorklet,
32
32
  bool shouldLockRuntime = true);
33
33
  WorkletsRunner(WorkletsRunner&&);
34
34
  ~WorkletsRunner();
@@ -20,7 +20,7 @@ class AudioEventHandlerRegistry : public IAudioEventHandlerRegistry {
20
20
  explicit AudioEventHandlerRegistry(
21
21
  jsi::Runtime *runtime,
22
22
  const std::shared_ptr<react::CallInvoker> &callInvoker);
23
- ~AudioEventHandlerRegistry();
23
+ ~AudioEventHandlerRegistry() override;
24
24
 
25
25
  uint64_t registerHandler(const std::string &eventName, const std::shared_ptr<jsi::Function> &handler) override;
26
26
  void unregisterHandler(const std::string &eventName, uint64_t listenerId) override;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-audio-api",
3
- "version": "0.10.0-nightly-44925d7-20251105",
3
+ "version": "0.10.0",
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"