react-native-audio-api 0.6.5-rc.1 → 0.7.0-nightly-fba4835-20250717

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 (100) hide show
  1. package/README.md +4 -1
  2. package/android/src/main/cpp/audioapi/android/core/AudioDecoder.cpp +56 -47
  3. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +38 -8
  4. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.h +9 -3
  5. package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +4 -0
  6. package/android/src/main/java/com/swmansion/audioapi/system/LockScreenManager.kt +2 -2
  7. package/android/src/main/java/com/swmansion/audioapi/system/MediaNotificationManager.kt +2 -2
  8. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionCallback.kt +2 -2
  9. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +46 -0
  10. package/android/src/main/res/drawable/skip_backward_15.xml +16 -0
  11. package/android/src/main/res/drawable/skip_forward_15.xml +16 -0
  12. package/android/src/oldarch/NativeAudioAPIModuleSpec.java +4 -0
  13. package/common/cpp/audioapi/HostObjects/AudioBufferBaseSourceNodeHostObject.h +9 -0
  14. package/common/cpp/audioapi/HostObjects/AudioBufferSourceNodeHostObject.h +3 -5
  15. package/common/cpp/audioapi/HostObjects/AudioScheduledSourceNodeHostObject.h +11 -2
  16. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +24 -23
  17. package/common/cpp/audioapi/core/AudioContext.cpp +6 -4
  18. package/common/cpp/audioapi/core/AudioContext.h +1 -1
  19. package/common/cpp/audioapi/core/AudioParam.cpp +18 -4
  20. package/common/cpp/audioapi/core/AudioParam.h +3 -0
  21. package/common/cpp/audioapi/core/BaseAudioContext.cpp +3 -3
  22. package/common/cpp/audioapi/core/BaseAudioContext.h +4 -3
  23. package/common/cpp/audioapi/core/OfflineAudioContext.cpp +2 -1
  24. package/common/cpp/audioapi/core/OfflineAudioContext.h +1 -1
  25. package/common/cpp/audioapi/core/effects/PeriodicWave.cpp +1 -1
  26. package/common/cpp/audioapi/core/inputs/AudioRecorder.h +1 -0
  27. package/common/cpp/audioapi/core/sources/AudioBuffer.h +1 -0
  28. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +11 -0
  29. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +4 -1
  30. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +11 -0
  31. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +2 -1
  32. package/common/cpp/audioapi/core/utils/AudioDecoder.h +38 -1
  33. package/common/cpp/audioapi/core/utils/AudioNodeDestructor.h +1 -0
  34. package/common/cpp/audioapi/core/utils/AudioNodeManager.h +1 -2
  35. package/common/cpp/audioapi/dsp/AudioUtils.cpp +1 -1
  36. package/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp +47 -17
  37. package/common/cpp/audioapi/events/AudioEventHandlerRegistry.h +6 -5
  38. package/common/cpp/audioapi/events/IAudioEventHandlerRegistry.h +25 -0
  39. package/common/cpp/audioapi/jsi/JsiPromise.cpp +1 -0
  40. package/common/cpp/audioapi/libs/audio-stretch/stretch.c +610 -0
  41. package/common/cpp/audioapi/libs/audio-stretch/stretch.h +49 -0
  42. package/common/cpp/audioapi/utils/AudioArray.h +1 -0
  43. package/common/cpp/audioapi/utils/CircularAudioArray.h +1 -0
  44. package/common/cpp/test/CMakeLists.txt +63 -0
  45. package/common/cpp/test/GainTest.cpp +78 -0
  46. package/common/cpp/test/MockAudioEventHandlerRegistry.h +22 -0
  47. package/common/cpp/test/OscillatorTest.cpp +22 -0
  48. package/common/cpp/test/RunTests.sh +26 -0
  49. package/ios/audioapi/ios/AudioAPIModule.mm +17 -8
  50. package/ios/audioapi/ios/core/AudioDecoder.mm +37 -31
  51. package/ios/audioapi/ios/core/IOSAudioPlayer.h +2 -1
  52. package/ios/audioapi/ios/core/IOSAudioPlayer.mm +5 -2
  53. package/ios/audioapi/ios/system/AudioSessionManager.h +4 -0
  54. package/ios/audioapi/ios/system/AudioSessionManager.mm +26 -0
  55. package/ios/audioapi/ios/system/LockScreenManager.mm +2 -0
  56. package/lib/commonjs/core/AudioBufferSourceNode.js +2 -2
  57. package/lib/commonjs/core/AudioBufferSourceNode.js.map +1 -1
  58. package/lib/commonjs/core/AudioScheduledSourceNode.js +4 -4
  59. package/lib/commonjs/core/AudioScheduledSourceNode.js.map +1 -1
  60. package/lib/commonjs/core/BaseAudioContext.js +7 -6
  61. package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
  62. package/lib/commonjs/plugin/withAudioAPI.js +1 -1
  63. package/lib/commonjs/plugin/withAudioAPI.js.map +1 -1
  64. package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -1
  65. package/lib/commonjs/system/AudioManager.js +3 -0
  66. package/lib/commonjs/system/AudioManager.js.map +1 -1
  67. package/lib/module/core/AudioBufferSourceNode.js +2 -2
  68. package/lib/module/core/AudioBufferSourceNode.js.map +1 -1
  69. package/lib/module/core/AudioScheduledSourceNode.js +4 -4
  70. package/lib/module/core/AudioScheduledSourceNode.js.map +1 -1
  71. package/lib/module/core/BaseAudioContext.js +7 -6
  72. package/lib/module/core/BaseAudioContext.js.map +1 -1
  73. package/lib/module/plugin/withAudioAPI.js +1 -1
  74. package/lib/module/plugin/withAudioAPI.js.map +1 -1
  75. package/lib/module/specs/NativeAudioAPIModule.js.map +1 -1
  76. package/lib/module/system/AudioManager.js +3 -0
  77. package/lib/module/system/AudioManager.js.map +1 -1
  78. package/lib/typescript/core/AudioBufferSourceNode.d.ts.map +1 -1
  79. package/lib/typescript/core/AudioScheduledSourceNode.d.ts +2 -2
  80. package/lib/typescript/core/BaseAudioContext.d.ts +4 -1
  81. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  82. package/lib/typescript/interfaces.d.ts +3 -3
  83. package/lib/typescript/interfaces.d.ts.map +1 -1
  84. package/lib/typescript/specs/NativeAudioAPIModule.d.ts +2 -1
  85. package/lib/typescript/specs/NativeAudioAPIModule.d.ts.map +1 -1
  86. package/lib/typescript/system/AudioManager.d.ts +2 -1
  87. package/lib/typescript/system/AudioManager.d.ts.map +1 -1
  88. package/lib/typescript/system/types.d.ts +11 -0
  89. package/lib/typescript/system/types.d.ts.map +1 -1
  90. package/package.json +1 -1
  91. package/src/core/AudioBufferSourceNode.ts +2 -8
  92. package/src/core/AudioScheduledSourceNode.ts +4 -4
  93. package/src/core/BaseAudioContext.ts +12 -9
  94. package/src/interfaces.ts +6 -6
  95. package/src/plugin/withAudioAPI.ts +1 -1
  96. package/src/specs/NativeAudioAPIModule.ts +4 -1
  97. package/src/system/AudioManager.ts +10 -1
  98. package/src/system/types.ts +14 -0
  99. package/android/src/main/res/drawable/skip_backward_10.xml +0 -9
  100. package/android/src/main/res/drawable/skip_forward_10.xml +0 -9
@@ -1,5 +1,6 @@
1
1
  #include <audioapi/core/AudioParam.h>
2
2
  #include <audioapi/core/BaseAudioContext.h>
3
+ #include <audioapi/core/utils/Locker.h>
3
4
  #include <audioapi/dsp/AudioUtils.h>
4
5
  #include <audioapi/dsp/VectorMath.h>
5
6
  #include <audioapi/utils/AudioArray.h>
@@ -17,10 +18,11 @@ AudioParam::AudioParam(
17
18
  minValue_(minValue),
18
19
  maxValue_(maxValue),
19
20
  context_(context),
20
- audioBus_(std::make_shared<AudioBus>(
21
- RENDER_QUANTUM_SIZE,
22
- 1,
23
- context->getSampleRate())) {
21
+ audioBus_(
22
+ std::make_shared<AudioBus>(
23
+ RENDER_QUANTUM_SIZE,
24
+ 1,
25
+ context->getSampleRate())) {
24
26
  startTime_ = 0;
25
27
  endTime_ = 0;
26
28
  startValue_ = value_;
@@ -46,11 +48,16 @@ float AudioParam::getMaxValue() const {
46
48
  return maxValue_;
47
49
  }
48
50
 
51
+ std::mutex &AudioParam::getQueueLock() {
52
+ return queueLock_;
53
+ }
54
+
49
55
  void AudioParam::setValue(float value) {
50
56
  value_ = std::clamp(value, minValue_, maxValue_);
51
57
  }
52
58
 
53
59
  float AudioParam::getValueAtTime(double time) {
60
+ Locker lock(getQueueLock());
54
61
  if (endTime_ < time && !eventsQueue_.empty()) {
55
62
  auto event = eventsQueue_.front();
56
63
  startTime_ = event.getStartTime();
@@ -83,6 +90,7 @@ void AudioParam::setValueAtTime(float value, double startTime) {
83
90
  return endValue;
84
91
  };
85
92
 
93
+ Locker lock(getQueueLock());
86
94
  auto event = ParamChangeEvent(
87
95
  startTime,
88
96
  startTime,
@@ -116,6 +124,7 @@ void AudioParam::linearRampToValueAtTime(float value, double endTime) {
116
124
  return endValue;
117
125
  };
118
126
 
127
+ Locker lock(getQueueLock());
119
128
  auto event = ParamChangeEvent(
120
129
  getQueueEndTime(),
121
130
  endTime,
@@ -150,6 +159,7 @@ void AudioParam::exponentialRampToValueAtTime(float value, double endTime) {
150
159
  return endValue;
151
160
  };
152
161
 
162
+ Locker lock(getQueueLock());
153
163
  auto event = ParamChangeEvent(
154
164
  getQueueEndTime(),
155
165
  endTime,
@@ -180,6 +190,7 @@ void AudioParam::setTargetAtTime(
180
190
  (startValue - target) * exp(-(time - startTime) / timeConstant));
181
191
  };
182
192
 
193
+ Locker lock(getQueueLock());
183
194
  auto event = ParamChangeEvent(
184
195
  startTime,
185
196
  startTime,
@@ -224,6 +235,7 @@ void AudioParam::setValueCurveAtTime(
224
235
  return endValue;
225
236
  };
226
237
 
238
+ Locker lock(getQueueLock());
227
239
  auto event = ParamChangeEvent(
228
240
  startTime,
229
241
  startTime + duration,
@@ -235,6 +247,7 @@ void AudioParam::setValueCurveAtTime(
235
247
  }
236
248
 
237
249
  void AudioParam::cancelScheduledValues(double cancelTime) {
250
+ Locker lock(getQueueLock());
238
251
  auto it = eventsQueue_.rbegin();
239
252
  while (it->getEndTime() >= cancelTime) {
240
253
  if (it->getStartTime() >= cancelTime ||
@@ -247,6 +260,7 @@ void AudioParam::cancelScheduledValues(double cancelTime) {
247
260
  }
248
261
 
249
262
  void AudioParam::cancelAndHoldAtTime(double cancelTime) {
263
+ Locker lock(getQueueLock());
250
264
  auto it = eventsQueue_.rbegin();
251
265
  while (it->getEndTime() >= cancelTime) {
252
266
  if (it->getStartTime() >= cancelTime) {
@@ -10,6 +10,7 @@
10
10
  #include <vector>
11
11
  #include <unordered_set>
12
12
  #include <cstddef>
13
+ #include <mutex>
13
14
 
14
15
  namespace audioapi {
15
16
 
@@ -50,6 +51,7 @@ class AudioParam {
50
51
  std::deque<ParamChangeEvent> eventsQueue_;
51
52
  std::unordered_set<AudioNode *> inputNodes_;
52
53
  std::shared_ptr<AudioBus> audioBus_;
54
+ std::mutex queueLock_;
53
55
 
54
56
  double startTime_;
55
57
  double endTime_;
@@ -58,6 +60,7 @@ class AudioParam {
58
60
  std::function<float(double, double, float, float, double)> calculateValue_;
59
61
  std::vector<std::shared_ptr<AudioBus>> inputBuses_ = {};
60
62
 
63
+ std::mutex &getQueueLock();
61
64
  double getQueueEndTime();
62
65
  float getQueueEndValue();
63
66
  void updateQueue(ParamChangeEvent &event);
@@ -19,7 +19,7 @@
19
19
  namespace audioapi {
20
20
 
21
21
  BaseAudioContext::BaseAudioContext(
22
- const std::shared_ptr<AudioEventHandlerRegistry>
22
+ const std::shared_ptr<IAudioEventHandlerRegistry>
23
23
  &audioEventHandlerRegistry) {
24
24
  nodeManager_ = std::make_shared<AudioNodeManager>();
25
25
  destination_ = std::make_shared<AudioDestinationNode>(this);
@@ -141,8 +141,8 @@ std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioData(
141
141
  }
142
142
 
143
143
  std::shared_ptr<AudioBuffer> BaseAudioContext::decodeWithPCMInBase64(
144
- const std::string &data) {
145
- auto audioBus = audioDecoder_->decodeWithPCMInBase64(data);
144
+ const std::string &data, float playbackSpeed) {
145
+ auto audioBus = audioDecoder_->decodeWithPCMInBase64(data, playbackSpeed);
146
146
 
147
147
  if (!audioBus) {
148
148
  return nullptr;
@@ -29,10 +29,11 @@ class AudioBufferQueueSourceNode;
29
29
  class AudioDecoder;
30
30
  class AnalyserNode;
31
31
  class AudioEventHandlerRegistry;
32
+ class IAudioEventHandlerRegistry;
32
33
 
33
34
  class BaseAudioContext {
34
35
  public:
35
- explicit BaseAudioContext(const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry);
36
+ explicit BaseAudioContext(const std::shared_ptr<IAudioEventHandlerRegistry> &audioEventHandlerRegistry);
36
37
  virtual ~BaseAudioContext() = default;
37
38
 
38
39
  std::string getState();
@@ -58,7 +59,7 @@ class BaseAudioContext {
58
59
 
59
60
  std::shared_ptr<AudioBuffer> decodeAudioDataSource(const std::string &path);
60
61
  std::shared_ptr<AudioBuffer> decodeAudioData(const void *data, size_t size);
61
- std::shared_ptr<AudioBuffer> decodeWithPCMInBase64(const std::string &data);
62
+ std::shared_ptr<AudioBuffer> decodeWithPCMInBase64(const std::string &data, float playbackSpeed);
62
63
 
63
64
  std::shared_ptr<PeriodicWave> getBasicWaveForm(OscillatorType type);
64
65
  [[nodiscard]] float getNyquistFrequency() const;
@@ -86,7 +87,7 @@ class BaseAudioContext {
86
87
  std::shared_ptr<PeriodicWave> cachedTriangleWave_ = nullptr;
87
88
 
88
89
  public:
89
- std::shared_ptr<AudioEventHandlerRegistry> audioEventHandlerRegistry_;
90
+ std::shared_ptr<IAudioEventHandlerRegistry> audioEventHandlerRegistry_;
90
91
  };
91
92
 
92
93
  } // namespace audioapi
@@ -22,7 +22,8 @@ OfflineAudioContext::OfflineAudioContext(
22
22
  int numberOfChannels,
23
23
  size_t length,
24
24
  float sampleRate,
25
- const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry)
25
+ const std::shared_ptr<IAudioEventHandlerRegistry>
26
+ &audioEventHandlerRegistry)
26
27
  : BaseAudioContext(audioEventHandlerRegistry),
27
28
  length_(length),
28
29
  numberOfChannels_(numberOfChannels),
@@ -14,7 +14,7 @@ using OfflineAudioContextResultCallback = std::function<void(std::shared_ptr<Aud
14
14
 
15
15
  class OfflineAudioContext : public BaseAudioContext {
16
16
  public:
17
- explicit OfflineAudioContext(int numberOfChannels, size_t length, float sampleRate, const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry);
17
+ explicit OfflineAudioContext(int numberOfChannels, size_t length, float sampleRate, const std::shared_ptr<IAudioEventHandlerRegistry> &audioEventHandlerRegistry);
18
18
  ~OfflineAudioContext() override;
19
19
 
20
20
  void resume();
@@ -118,7 +118,7 @@ int PeriodicWave::getNumberOfPartialsPerRange(int rangeIndex) const {
118
118
  auto centsToCull = static_cast<float>(rangeIndex) * CentsPerRange;
119
119
 
120
120
  // A value from 0 -> 1 representing what fraction of the partials to keep.
121
- auto cullingScale = std::powf(2, -centsToCull / 1200);
121
+ auto cullingScale = std::pow(2, -centsToCull / 1200);
122
122
 
123
123
  // The very top range will have all the partials culled.
124
124
  int numberOfPartials =
@@ -1,6 +1,7 @@
1
1
  #pragma once
2
2
 
3
3
  #include <memory>
4
+ #include <atomic>
4
5
 
5
6
  namespace audioapi {
6
7
  class AudioBus;
@@ -5,6 +5,7 @@
5
5
  #include <string>
6
6
  #include <vector>
7
7
  #include <cstddef>
8
+ #include <cstring>
8
9
 
9
10
  namespace audioapi {
10
11
 
@@ -41,6 +41,17 @@ std::shared_ptr<AudioParam> AudioBufferBaseSourceNode::getPlaybackRateParam()
41
41
  return playbackRateParam_;
42
42
  }
43
43
 
44
+ void AudioBufferBaseSourceNode::clearOnPositionChangedCallback() {
45
+ if (onPositionChangedCallbackId_ == 0 || context_ == nullptr ||
46
+ context_->audioEventHandlerRegistry_ == nullptr) {
47
+ return;
48
+ }
49
+
50
+ context_->audioEventHandlerRegistry_->unregisterHandler(
51
+ "positionChanged", onPositionChangedCallbackId_);
52
+ onPositionChangedCallbackId_ = 0;
53
+ }
54
+
44
55
  void AudioBufferBaseSourceNode::setOnPositionChangedCallbackId(
45
56
  uint64_t callbackId) {
46
57
  onPositionChangedCallbackId_ = callbackId;
@@ -4,6 +4,8 @@
4
4
  #include <audioapi/libs/signalsmith-stretch/signalsmith-stretch.h>
5
5
 
6
6
  #include <memory>
7
+ #include <mutex>
8
+ #include <atomic>
7
9
 
8
10
  namespace audioapi {
9
11
 
@@ -18,6 +20,7 @@ class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
18
20
  [[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
19
21
  [[nodiscard]] std::shared_ptr<AudioParam> getPlaybackRateParam() const;
20
22
 
23
+ void clearOnPositionChangedCallback();
21
24
  void setOnPositionChangedCallbackId(uint64_t callbackId);
22
25
  void setOnPositionChangedInterval(int interval);
23
26
  [[nodiscard]] int getOnPositionChangedInterval();
@@ -36,7 +39,7 @@ class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
36
39
  // internal helper
37
40
  double vReadIndex_;
38
41
 
39
- uint64_t onPositionChangedCallbackId_ = 0; // 0 means no callback
42
+ std::atomic<uint64_t> onPositionChangedCallbackId_ = 0; // 0 means no callback
40
43
  int onPositionChangedInterval_;
41
44
  int onPositionChangedTime_ = 0;
42
45
 
@@ -54,6 +54,17 @@ bool AudioScheduledSourceNode::isStopScheduled() {
54
54
  return playbackState_ == PlaybackState::STOP_SCHEDULED;
55
55
  }
56
56
 
57
+ void AudioScheduledSourceNode::clearOnEndedCallback() {
58
+ if (onEndedCallbackId_ == 0 || context_ == nullptr ||
59
+ context_->audioEventHandlerRegistry_ == nullptr) {
60
+ return;
61
+ }
62
+
63
+ context_->audioEventHandlerRegistry_->unregisterHandler(
64
+ "ended", onEndedCallbackId_);
65
+ onEndedCallbackId_ = 0;
66
+ }
67
+
57
68
  void AudioScheduledSourceNode::setOnEndedCallbackId(const uint64_t callbackId) {
58
69
  onEndedCallbackId_ = callbackId;
59
70
  }
@@ -38,6 +38,7 @@ class AudioScheduledSourceNode : public AudioNode {
38
38
  bool isFinished();
39
39
  bool isStopScheduled();
40
40
 
41
+ void clearOnEndedCallback();
41
42
  void setOnEndedCallbackId(uint64_t callbackId);
42
43
 
43
44
  void disable() override;
@@ -48,7 +49,7 @@ class AudioScheduledSourceNode : public AudioNode {
48
49
 
49
50
  PlaybackState playbackState_;
50
51
 
51
- uint64_t onEndedCallbackId_ = 0;
52
+ std::atomic<uint64_t> onEndedCallbackId_ = 0;
52
53
 
53
54
  void updatePlaybackInfo(
54
55
  const std::shared_ptr<AudioBus>& processingBus,
@@ -1,7 +1,9 @@
1
1
  #pragma once
2
2
 
3
+ #include <audioapi/libs/audio-stretch/stretch.h>
3
4
  #include <memory>
4
5
  #include <string>
6
+ #include <vector>
5
7
 
6
8
  namespace audioapi {
7
9
 
@@ -13,10 +15,45 @@ class AudioDecoder {
13
15
 
14
16
  [[nodiscard]] std::shared_ptr<AudioBus> decodeWithFilePath(const std::string &path) const;
15
17
  [[nodiscard]] std::shared_ptr<AudioBus> decodeWithMemoryBlock(const void *data, size_t size) const;
16
- [[nodiscard]] std::shared_ptr<AudioBus> decodeWithPCMInBase64(const std::string &data) const;
18
+ [[nodiscard]] std::shared_ptr<AudioBus> decodeWithPCMInBase64(const std::string &data, float playbackSpeed) const;
17
19
 
18
20
  private:
19
21
  float sampleRate_;
22
+ int numChannels_ = 2;
23
+
24
+ void changePlaybackSpeedIfNeeded(std::vector<int16_t> &buffer, size_t framesDecoded, int numChannels, float playbackSpeed) const {
25
+ if (playbackSpeed == 1.0f) {
26
+ return;
27
+ }
28
+
29
+ auto stretcher = stretch_init(static_cast<int>(sampleRate_ / 333.0f), static_cast<int>(sampleRate_ / 55.0f), numChannels, 0x1);
30
+
31
+ int maxOutputFrames = stretch_output_capacity(stretcher, static_cast<int>(framesDecoded), 1 / playbackSpeed);
32
+ std::vector<int16_t> stretchedBuffer(maxOutputFrames);
33
+
34
+ int outputFrames = stretch_samples(
35
+ stretcher,
36
+ buffer.data(),
37
+ static_cast<int>(framesDecoded),
38
+ stretchedBuffer.data(),
39
+ 1 / playbackSpeed
40
+ );
41
+
42
+ outputFrames += stretch_flush(stretcher, stretchedBuffer.data() + (outputFrames));
43
+ stretchedBuffer.resize(outputFrames);
44
+
45
+ buffer = stretchedBuffer;
46
+
47
+ stretch_deinit(stretcher);
48
+ }
49
+
50
+ [[nodiscard]] static inline int16_t floatToInt16(float sample) {
51
+ return static_cast<int16_t>(sample * 32768.0f);
52
+ }
53
+
54
+ [[nodiscard]] static inline float int16ToFloat(int16_t sample) {
55
+ return static_cast<float>(sample) / 32768.0f;
56
+ }
20
57
  };
21
58
 
22
59
  } // namespace audioapi
@@ -4,6 +4,7 @@
4
4
  #include <mutex>
5
5
  #include <thread>
6
6
  #include <atomic>
7
+ #include <functional>
7
8
  #include <vector>
8
9
  #include <memory>
9
10
 
@@ -20,8 +20,6 @@ class AudioNodeManager {
20
20
  AudioNodeManager() = default;
21
21
  ~AudioNodeManager();
22
22
 
23
- std::mutex &getGraphLock();
24
-
25
23
  void preProcessGraph();
26
24
 
27
25
  void addPendingNodeConnection(
@@ -62,6 +60,7 @@ class AudioNodeManager {
62
60
  ConnectionType>>
63
61
  audioParamToConnect_;
64
62
 
63
+ std::mutex &getGraphLock();
65
64
  void settlePendingConnections();
66
65
  void cleanupNode(const std::shared_ptr<AudioNode> &node);
67
66
  void prepareNodesForDestruction();
@@ -28,6 +28,6 @@ float linearToDecibels(float value) {
28
28
  }
29
29
 
30
30
  float decibelsToLinear(float value) {
31
- return powf(10, value / 20);
31
+ return pow(10, value / 20);
32
32
  }
33
33
  } // namespace audioapi::dsp
@@ -4,7 +4,8 @@ namespace audioapi {
4
4
 
5
5
  AudioEventHandlerRegistry::AudioEventHandlerRegistry(
6
6
  jsi::Runtime *runtime,
7
- const std::shared_ptr<react::CallInvoker> &callInvoker) {
7
+ const std::shared_ptr<react::CallInvoker> &callInvoker)
8
+ : IAudioEventHandlerRegistry() {
8
9
  runtime_ = runtime;
9
10
  callInvoker_ = callInvoker;
10
11
 
@@ -91,8 +92,18 @@ void AudioEventHandlerRegistry::invokeHandlerWithEventBody(
91
92
  continue;
92
93
  }
93
94
 
94
- auto eventObject = createEventObject(body);
95
- handler->call(*runtime_, eventObject);
95
+ try {
96
+ auto eventObject = createEventObject(body);
97
+ handler->call(*runtime_, eventObject);
98
+ } catch (const std::exception &e) {
99
+ // re-throw the exception to be handled by the caller
100
+ // std::exception is safe to parse by the rn bridge
101
+ throw;
102
+ } catch (...) {
103
+ printf(
104
+ "Unknown exception occurred while invoking handler for event: %s\n",
105
+ eventName.c_str());
106
+ }
96
107
  }
97
108
  });
98
109
  }
@@ -122,8 +133,26 @@ void AudioEventHandlerRegistry::invokeHandlerWithEventBody(
122
133
  return;
123
134
  }
124
135
 
125
- auto eventObject = createEventObject(body);
126
- handlerIt->second->call(*runtime_, eventObject);
136
+ // Depending on how the AudioBufferSourceNode is handled on the JS side,
137
+ // it sometimes might enter race condition where the ABSN is deleted on JS
138
+ // side, but it is still processed on the audio thread, leading to a crash
139
+ // when f.e. `positionChanged` event is triggered.
140
+
141
+ // In case of debugging this, please increment the hours spent counter
142
+
143
+ // Hours spent on this: 5
144
+ try {
145
+ auto eventObject = createEventObject(body);
146
+ handlerIt->second->call(*runtime_, eventObject);
147
+ } catch (const std::exception &e) {
148
+ // re-throw the exception to be handled by the caller
149
+ // std::exception is safe to parse by the rn bridge
150
+ throw;
151
+ } catch (...) {
152
+ printf(
153
+ "Unknown exception occurred while invoking handler for event: %s\n",
154
+ eventName.c_str());
155
+ }
127
156
  });
128
157
  }
129
158
 
@@ -135,19 +164,20 @@ jsi::Object AudioEventHandlerRegistry::createEventObject(
135
164
  const auto name = pair.first.data();
136
165
  const auto &value = pair.second;
137
166
 
138
- if (holds_alternative<int>(value)) {
139
- eventObject.setProperty(*runtime_, name, get<int>(value));
140
- } else if (holds_alternative<double>(value)) {
141
- eventObject.setProperty(*runtime_, name, get<double>(value));
142
- } else if (holds_alternative<float>(value)) {
143
- eventObject.setProperty(*runtime_, name, get<float>(value));
144
- } else if (holds_alternative<bool>(value)) {
145
- eventObject.setProperty(*runtime_, name, get<bool>(value));
146
- } else if (holds_alternative<std::string>(value)) {
147
- eventObject.setProperty(*runtime_, name, get<std::string>(value));
148
- } else if (holds_alternative<std::shared_ptr<jsi::HostObject>>(value)) {
167
+ if (std::holds_alternative<int>(value)) {
168
+ eventObject.setProperty(*runtime_, name, std::get<int>(value));
169
+ } else if (std::holds_alternative<double>(value)) {
170
+ eventObject.setProperty(*runtime_, name, std::get<double>(value));
171
+ } else if (std::holds_alternative<float>(value)) {
172
+ eventObject.setProperty(*runtime_, name, std::get<float>(value));
173
+ } else if (std::holds_alternative<bool>(value)) {
174
+ eventObject.setProperty(*runtime_, name, std::get<bool>(value));
175
+ } else if (std::holds_alternative<std::string>(value)) {
176
+ eventObject.setProperty(*runtime_, name, std::get<std::string>(value));
177
+ } else if (std::holds_alternative<std::shared_ptr<jsi::HostObject>>(
178
+ value)) {
149
179
  auto hostObject = jsi::Object::createFromHostObject(
150
- *runtime_, get<std::shared_ptr<jsi::HostObject>>(value));
180
+ *runtime_, std::get<std::shared_ptr<jsi::HostObject>>(value));
151
181
  eventObject.setProperty(*runtime_, name, hostObject);
152
182
  }
153
183
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  #include <jsi/jsi.h>
4
4
  #include <ReactCommon/CallInvoker.h>
5
+ #include <audioapi/events/IAudioEventHandlerRegistry.h>
5
6
  #include <memory>
6
7
  #include <unordered_map>
7
8
  #include <array>
@@ -14,18 +15,18 @@ using namespace facebook;
14
15
 
15
16
  using EventValue = std::variant<int, float, double, std::string, bool, std::shared_ptr<jsi::HostObject>>;
16
17
 
17
- class AudioEventHandlerRegistry {
18
+ class AudioEventHandlerRegistry : public IAudioEventHandlerRegistry {
18
19
  public:
19
20
  explicit AudioEventHandlerRegistry(
20
21
  jsi::Runtime *runtime,
21
22
  const std::shared_ptr<react::CallInvoker> &callInvoker);
22
23
  ~AudioEventHandlerRegistry();
23
24
 
24
- uint64_t registerHandler(const std::string &eventName, const std::shared_ptr<jsi::Function> &handler);
25
- void unregisterHandler(const std::string &eventName, uint64_t listenerId);
25
+ uint64_t registerHandler(const std::string &eventName, const std::shared_ptr<jsi::Function> &handler) override;
26
+ void unregisterHandler(const std::string &eventName, uint64_t listenerId) override;
26
27
 
27
- void invokeHandlerWithEventBody(const std::string &eventName, const std::unordered_map<std::string, EventValue> &body);
28
- void invokeHandlerWithEventBody(const std::string &eventName, uint64_t listenerId, const std::unordered_map<std::string, EventValue> &body);
28
+ void invokeHandlerWithEventBody(const std::string &eventName, const std::unordered_map<std::string, EventValue> &body) override;
29
+ void invokeHandlerWithEventBody(const std::string &eventName, uint64_t listenerId, const std::unordered_map<std::string, EventValue> &body) override;
29
30
 
30
31
  private:
31
32
  std::atomic<uint64_t> listenerIdCounter_{1}; // Atomic counter for listener IDs
@@ -0,0 +1,25 @@
1
+ #pragma once
2
+
3
+ #include <jsi/jsi.h>
4
+ #include <ReactCommon/CallInvoker.h>
5
+ #include <unordered_map>
6
+ #include <variant>
7
+ #include <string>
8
+ #include <memory>
9
+
10
+ namespace audioapi {
11
+
12
+ using EventValue = std::variant<int, float, double, std::string, bool, std::shared_ptr<facebook::jsi::HostObject>>;
13
+
14
+ class IAudioEventHandlerRegistry {
15
+ public:
16
+ virtual ~IAudioEventHandlerRegistry() = default;
17
+
18
+ virtual uint64_t registerHandler(const std::string &eventName, const std::shared_ptr<facebook::jsi::Function> &handler) = 0;
19
+ virtual void unregisterHandler(const std::string &eventName, uint64_t listenerId) = 0;
20
+
21
+ virtual void invokeHandlerWithEventBody(const std::string &eventName, const std::unordered_map<std::string, EventValue> &body) = 0;
22
+ virtual void invokeHandlerWithEventBody(const std::string &eventName, uint64_t listenerId, const std::unordered_map<std::string, EventValue> &body) = 0;
23
+ };
24
+
25
+ } // namespace audioapi
@@ -1,4 +1,5 @@
1
1
  #include <audioapi/jsi/JsiPromise.h>
2
+ #include <stdexcept>
2
3
 
3
4
  namespace audioapi {
4
5