react-native-audio-api 0.6.3-rc.1 → 0.6.4-nightly-a960beb-20250703

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 (49) hide show
  1. package/android/src/main/cpp/audioapi/android/AudioAPIModule.cpp +11 -3
  2. package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +1 -1
  3. package/android/src/main/java/com/swmansion/audioapi/system/AudioFocusListener.kt +5 -5
  4. package/android/src/main/java/com/swmansion/audioapi/system/LockScreenManager.kt +1 -2
  5. package/common/cpp/audioapi/HostObjects/AudioBufferBaseSourceNodeHostObject.h +8 -1
  6. package/common/cpp/audioapi/core/AudioContext.cpp +2 -1
  7. package/common/cpp/audioapi/core/AudioContext.h +1 -1
  8. package/common/cpp/audioapi/core/AudioParam.cpp +17 -5
  9. package/common/cpp/audioapi/core/AudioParam.h +3 -0
  10. package/common/cpp/audioapi/core/BaseAudioContext.cpp +7 -1
  11. package/common/cpp/audioapi/core/BaseAudioContext.h +5 -2
  12. package/common/cpp/audioapi/core/OfflineAudioContext.cpp +2 -1
  13. package/common/cpp/audioapi/core/OfflineAudioContext.h +1 -1
  14. package/common/cpp/audioapi/core/effects/PeriodicWave.cpp +1 -1
  15. package/common/cpp/audioapi/core/inputs/AudioRecorder.cpp +4 -2
  16. package/common/cpp/audioapi/core/inputs/AudioRecorder.h +1 -0
  17. package/common/cpp/audioapi/core/sources/AudioBuffer.h +1 -0
  18. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +15 -1
  19. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +7 -4
  20. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +13 -2
  21. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +1 -0
  22. package/common/cpp/audioapi/core/utils/AudioNodeDestructor.h +1 -0
  23. package/common/cpp/audioapi/core/utils/AudioNodeManager.h +1 -2
  24. package/common/cpp/audioapi/dsp/AudioUtils.cpp +1 -1
  25. package/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp +80 -29
  26. package/common/cpp/audioapi/events/AudioEventHandlerRegistry.h +9 -5
  27. package/common/cpp/audioapi/events/IAudioEventHandlerRegistry.h +25 -0
  28. package/common/cpp/audioapi/utils/AudioArray.h +1 -0
  29. package/common/cpp/audioapi/utils/CircularAudioArray.h +1 -0
  30. package/common/cpp/test/CMakeLists.txt +79 -0
  31. package/common/cpp/test/MockAudioEventHandlerRegistry.h +22 -0
  32. package/common/cpp/test/OscillatorTest.cpp +22 -0
  33. package/common/cpp/test/RunTests.sh +26 -0
  34. package/ios/audioapi/ios/AudioAPIModule.mm +11 -12
  35. package/lib/commonjs/core/AudioBufferBaseSourceNode.js +10 -6
  36. package/lib/commonjs/core/AudioBufferBaseSourceNode.js.map +1 -1
  37. package/lib/commonjs/core/AudioScheduledSourceNode.js +6 -2
  38. package/lib/commonjs/core/AudioScheduledSourceNode.js.map +1 -1
  39. package/lib/module/core/AudioBufferBaseSourceNode.js +10 -6
  40. package/lib/module/core/AudioBufferBaseSourceNode.js.map +1 -1
  41. package/lib/module/core/AudioScheduledSourceNode.js +6 -2
  42. package/lib/module/core/AudioScheduledSourceNode.js.map +1 -1
  43. package/lib/typescript/core/AudioBufferBaseSourceNode.d.ts +6 -3
  44. package/lib/typescript/core/AudioBufferBaseSourceNode.d.ts.map +1 -1
  45. package/lib/typescript/core/AudioScheduledSourceNode.d.ts +2 -0
  46. package/lib/typescript/core/AudioScheduledSourceNode.d.ts.map +1 -1
  47. package/package.json +9 -9
  48. package/src/core/AudioBufferBaseSourceNode.ts +20 -7
  49. package/src/core/AudioScheduledSourceNode.ts +9 -1
@@ -58,11 +58,19 @@ void AudioAPIModule::invokeHandlerWithEventNameAndEventBody(
58
58
  } else if (value->isInstanceOf(jni::JFloat::javaClassStatic())) {
59
59
  body[name] = jni::static_ref_cast<jni::JFloat>(value)->value();
60
60
  } else if (value->isInstanceOf(jni::JBoolean::javaClassStatic())) {
61
- body[name] = jni::static_ref_cast<jni::JBoolean>(value)->value();
61
+ auto booleanValue = jni::static_ref_cast<jni::JBoolean>(value)->value();
62
+
63
+ if (booleanValue) {
64
+ body[name] = true;
65
+ } else {
66
+ body[name] = false;
67
+ }
62
68
  }
63
69
  }
64
70
 
65
- audioEventHandlerRegistry_->invokeHandlerWithEventBody(
66
- eventName->toStdString(), body);
71
+ if (audioEventHandlerRegistry_ != nullptr) {
72
+ audioEventHandlerRegistry_->invokeHandlerWithEventBody(
73
+ eventName->toStdString(), body);
74
+ }
67
75
  }
68
76
  } // namespace audioapi
@@ -60,7 +60,7 @@ class AudioAPIModule(
60
60
  enabled: Boolean,
61
61
  promise: Promise?,
62
62
  ) {
63
- // noting to do here
63
+ promise?.resolve(true)
64
64
  }
65
65
 
66
66
  override fun setAudioSessionOptions(
@@ -13,7 +13,7 @@ class AudioFocusListener(
13
13
  private val audioAPIModule: WeakReference<AudioAPIModule>,
14
14
  private val lockScreenManager: WeakReference<LockScreenManager>,
15
15
  ) : AudioManager.OnAudioFocusChangeListener {
16
- private var playOnAudioFocus = false
16
+ private var playOnAudioFocus: Boolean = false
17
17
  private var focusRequest: AudioFocusRequest? = null
18
18
 
19
19
  override fun onAudioFocusChange(focusChange: Int) {
@@ -23,7 +23,7 @@ class AudioFocusListener(
23
23
  playOnAudioFocus = false
24
24
  val body =
25
25
  HashMap<String, Any>().apply {
26
- put("value", "began")
26
+ put("type", "began")
27
27
  put("shouldResume", false)
28
28
  }
29
29
  audioAPIModule.get()?.invokeHandlerWithEventNameAndEventBody("interruption", body)
@@ -32,7 +32,7 @@ class AudioFocusListener(
32
32
  playOnAudioFocus = lockScreenManager.get()?.isPlaying == true
33
33
  val body =
34
34
  HashMap<String, Any>().apply {
35
- put("value", "began")
35
+ put("type", "began")
36
36
  put("shouldResume", playOnAudioFocus)
37
37
  }
38
38
  audioAPIModule.get()?.invokeHandlerWithEventNameAndEventBody("interruption", body)
@@ -41,14 +41,14 @@ class AudioFocusListener(
41
41
  if (playOnAudioFocus) {
42
42
  val body =
43
43
  HashMap<String, Any>().apply {
44
- put("value", "ended")
44
+ put("type", "ended")
45
45
  put("shouldResume", true)
46
46
  }
47
47
  audioAPIModule.get()?.invokeHandlerWithEventNameAndEventBody("interruption", body)
48
48
  } else {
49
49
  val body =
50
50
  HashMap<String, Any>().apply {
51
- put("value", "ended")
51
+ put("type", "ended")
52
52
  put("shouldResume", false)
53
53
  }
54
54
  audioAPIModule.get()?.invokeHandlerWithEventNameAndEventBody("interruption", body)
@@ -12,7 +12,6 @@ import androidx.media.app.NotificationCompat.MediaStyle
12
12
  import com.facebook.react.bridge.ReactApplicationContext
13
13
  import com.facebook.react.bridge.ReadableMap
14
14
  import com.facebook.react.bridge.ReadableType
15
- import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper.Companion.instance
16
15
  import com.swmansion.audioapi.R
17
16
  import java.io.IOException
18
17
  import java.lang.ref.WeakReference
@@ -250,7 +249,7 @@ class LockScreenManager(
250
249
  // If we are running the app in debug mode, the "local" image will be served from htt://localhost:8080, so we need to check for this case and load those images from URL
251
250
  if (local && !url.startsWith("http")) {
252
251
  // Gets the drawable from the RN's helper for local resources
253
- val helper = instance
252
+ val helper = com.facebook.react.views.imagehelper.ResourceDrawableIdHelper.instance
254
253
  val image = helper.getResourceDrawable(reactContext.get()!!, url)
255
254
 
256
255
  bitmap =
@@ -18,7 +18,8 @@ class AudioBufferBaseSourceNodeHostObject
18
18
  : AudioScheduledSourceNodeHostObject(node) {
19
19
  addGetters(
20
20
  JSI_EXPORT_PROPERTY_GETTER(AudioBufferBaseSourceNodeHostObject, detune),
21
- JSI_EXPORT_PROPERTY_GETTER(AudioBufferBaseSourceNodeHostObject, playbackRate));
21
+ JSI_EXPORT_PROPERTY_GETTER(AudioBufferBaseSourceNodeHostObject, playbackRate),
22
+ JSI_EXPORT_PROPERTY_GETTER(AudioBufferBaseSourceNodeHostObject, onPositionChangedInterval));
22
23
 
23
24
  addSetters(
24
25
  JSI_EXPORT_PROPERTY_SETTER(AudioBufferBaseSourceNodeHostObject, onPositionChanged),
@@ -49,6 +50,12 @@ class AudioBufferBaseSourceNodeHostObject
49
50
  sourceNode->setOnPositionChangedCallbackId(std::stoull(value.getString(runtime).utf8(runtime)));
50
51
  }
51
52
 
53
+ JSI_PROPERTY_GETTER(onPositionChangedInterval) {
54
+ auto sourceNode =
55
+ std::static_pointer_cast<AudioBufferBaseSourceNode>(node_);
56
+ return jsi::Value(sourceNode->getOnPositionChangedInterval());
57
+ }
58
+
52
59
  JSI_PROPERTY_SETTER(onPositionChangedInterval) {
53
60
  auto sourceNode =
54
61
  std::static_pointer_cast<AudioBufferBaseSourceNode>(node_);
@@ -13,7 +13,8 @@ namespace audioapi {
13
13
  AudioContext::AudioContext(
14
14
  float sampleRate,
15
15
  bool initSuspended,
16
- const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry)
16
+ const std::shared_ptr<IAudioEventHandlerRegistry>
17
+ &audioEventHandlerRegistry)
17
18
  : BaseAudioContext(audioEventHandlerRegistry) {
18
19
  #ifdef ANDROID
19
20
  audioPlayer_ = std::make_shared<AudioPlayer>(this->renderAudio(), sampleRate);
@@ -14,7 +14,7 @@ class IOSAudioPlayer;
14
14
 
15
15
  class AudioContext : public BaseAudioContext {
16
16
  public:
17
- explicit AudioContext(float sampleRate, bool initSuspended, const std::shared_ptr<AudioEventHandlerRegistry> &audioEventHandlerRegistry);
17
+ explicit AudioContext(float sampleRate, bool initSuspended, const std::shared_ptr<IAudioEventHandlerRegistry> &audioEventHandlerRegistry);
18
18
  ~AudioContext() override;
19
19
 
20
20
  void close();
@@ -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,11 +18,10 @@ AudioParam::AudioParam(
17
18
  minValue_(minValue),
18
19
  maxValue_(maxValue),
19
20
  context_(context),
20
- audioBus_(
21
- std::make_shared<AudioBus>(
22
- RENDER_QUANTUM_SIZE,
23
- 1,
24
- context->getSampleRate())) {
21
+ audioBus_(std::make_shared<AudioBus>(
22
+ RENDER_QUANTUM_SIZE,
23
+ 1,
24
+ context->getSampleRate())) {
25
25
  startTime_ = 0;
26
26
  endTime_ = 0;
27
27
  startValue_ = value_;
@@ -47,11 +47,16 @@ float AudioParam::getMaxValue() const {
47
47
  return maxValue_;
48
48
  }
49
49
 
50
+ std::mutex &AudioParam::getQueueLock() {
51
+ return queueLock_;
52
+ }
53
+
50
54
  void AudioParam::setValue(float value) {
51
55
  value_ = std::clamp(value, minValue_, maxValue_);
52
56
  }
53
57
 
54
58
  float AudioParam::getValueAtTime(double time) {
59
+ Locker lock(getQueueLock());
55
60
  if (endTime_ < time && !eventsQueue_.empty()) {
56
61
  auto event = eventsQueue_.front();
57
62
  startTime_ = event.getStartTime();
@@ -84,6 +89,7 @@ void AudioParam::setValueAtTime(float value, double startTime) {
84
89
  return endValue;
85
90
  };
86
91
 
92
+ Locker lock(getQueueLock());
87
93
  auto event = ParamChangeEvent(
88
94
  startTime,
89
95
  startTime,
@@ -117,6 +123,7 @@ void AudioParam::linearRampToValueAtTime(float value, double endTime) {
117
123
  return endValue;
118
124
  };
119
125
 
126
+ Locker lock(getQueueLock());
120
127
  auto event = ParamChangeEvent(
121
128
  getQueueEndTime(),
122
129
  endTime,
@@ -151,6 +158,7 @@ void AudioParam::exponentialRampToValueAtTime(float value, double endTime) {
151
158
  return endValue;
152
159
  };
153
160
 
161
+ Locker lock(getQueueLock());
154
162
  auto event = ParamChangeEvent(
155
163
  getQueueEndTime(),
156
164
  endTime,
@@ -181,6 +189,7 @@ void AudioParam::setTargetAtTime(
181
189
  (startValue - target) * exp(-(time - startTime) / timeConstant));
182
190
  };
183
191
 
192
+ Locker lock(getQueueLock());
184
193
  auto event = ParamChangeEvent(
185
194
  startTime,
186
195
  startTime,
@@ -225,6 +234,7 @@ void AudioParam::setValueCurveAtTime(
225
234
  return endValue;
226
235
  };
227
236
 
237
+ Locker lock(getQueueLock());
228
238
  auto event = ParamChangeEvent(
229
239
  startTime,
230
240
  startTime + duration,
@@ -236,6 +246,7 @@ void AudioParam::setValueCurveAtTime(
236
246
  }
237
247
 
238
248
  void AudioParam::cancelScheduledValues(double cancelTime) {
249
+ Locker lock(getQueueLock());
239
250
  auto it = eventsQueue_.rbegin();
240
251
  while (it->getEndTime() >= cancelTime) {
241
252
  if (it->getStartTime() >= cancelTime ||
@@ -248,6 +259,7 @@ void AudioParam::cancelScheduledValues(double cancelTime) {
248
259
  }
249
260
 
250
261
  void AudioParam::cancelAndHoldAtTime(double cancelTime) {
262
+ Locker lock(getQueueLock());
251
263
  auto it = eventsQueue_.rbegin();
252
264
  while (it->getEndTime() >= cancelTime) {
253
265
  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);
@@ -119,6 +119,7 @@ std::shared_ptr<AnalyserNode> BaseAudioContext::createAnalyser() {
119
119
 
120
120
  std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioDataSource(
121
121
  const std::string &path) {
122
+ #ifndef AUDIO_API_TEST_SUITE
122
123
  auto audioBus = audioDecoder_->decodeWithFilePath(path);
123
124
 
124
125
  if (!audioBus) {
@@ -126,11 +127,13 @@ std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioDataSource(
126
127
  }
127
128
 
128
129
  return std::make_shared<AudioBuffer>(audioBus);
130
+ #endif // AUDIO_API_TEST_SUITE
129
131
  }
130
132
 
131
133
  std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioData(
132
134
  const void *data,
133
135
  size_t size) {
136
+ #ifndef AUDIO_API_TEST_SUITE
134
137
  auto audioBus = audioDecoder_->decodeWithMemoryBlock(data, size);
135
138
 
136
139
  if (!audioBus) {
@@ -138,10 +141,12 @@ std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioData(
138
141
  }
139
142
 
140
143
  return std::make_shared<AudioBuffer>(audioBus);
144
+ #endif // AUDIO_API_TEST_SUITE
141
145
  }
142
146
 
143
147
  std::shared_ptr<AudioBuffer> BaseAudioContext::decodeWithPCMInBase64(
144
148
  const std::string &data) {
149
+ #ifndef AUDIO_API_TEST_SUITE
145
150
  auto audioBus = audioDecoder_->decodeWithPCMInBase64(data);
146
151
 
147
152
  if (!audioBus) {
@@ -149,6 +154,7 @@ std::shared_ptr<AudioBuffer> BaseAudioContext::decodeWithPCMInBase64(
149
154
  }
150
155
 
151
156
  return std::make_shared<AudioBuffer>(audioBus);
157
+ #endif // AUDIO_API_TEST_SUITE
152
158
  }
153
159
 
154
160
  AudioNodeManager *BaseAudioContext::getNodeManager() {
@@ -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();
@@ -56,9 +57,11 @@ class BaseAudioContext {
56
57
  int length);
57
58
  std::shared_ptr<AnalyserNode> createAnalyser();
58
59
 
60
+ #ifndef TESTING
59
61
  std::shared_ptr<AudioBuffer> decodeAudioDataSource(const std::string &path);
60
62
  std::shared_ptr<AudioBuffer> decodeAudioData(const void *data, size_t size);
61
63
  std::shared_ptr<AudioBuffer> decodeWithPCMInBase64(const std::string &data);
64
+ #endif //TESTING
62
65
 
63
66
  std::shared_ptr<PeriodicWave> getBasicWaveForm(OscillatorType type);
64
67
  [[nodiscard]] float getNyquistFrequency() const;
@@ -86,7 +89,7 @@ class BaseAudioContext {
86
89
  std::shared_ptr<PeriodicWave> cachedTriangleWave_ = nullptr;
87
90
 
88
91
  public:
89
- std::shared_ptr<AudioEventHandlerRegistry> audioEventHandlerRegistry_;
92
+ std::shared_ptr<IAudioEventHandlerRegistry> audioEventHandlerRegistry_;
90
93
  };
91
94
 
92
95
  } // 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 =
@@ -36,8 +36,10 @@ void AudioRecorder::invokeOnAudioReadyCallback(
36
36
  body.insert({"numFrames", numFrames});
37
37
  body.insert({"when", when});
38
38
 
39
- audioEventHandlerRegistry_->invokeHandlerWithEventBody(
40
- "audioReady", onAudioReadyCallbackId_, body);
39
+ if (audioEventHandlerRegistry_ != nullptr) {
40
+ audioEventHandlerRegistry_->invokeHandlerWithEventBody(
41
+ "audioReady", onAudioReadyCallbackId_, body);
42
+ }
41
43
  }
42
44
 
43
45
  void AudioRecorder::sendRemainingData() {
@@ -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
 
@@ -23,6 +23,15 @@ AudioBufferBaseSourceNode::AudioBufferBaseSourceNode(BaseAudioContext *context)
23
23
  std::make_shared<signalsmith::stretch::SignalsmithStretch<float>>();
24
24
  }
25
25
 
26
+ AudioBufferBaseSourceNode::~AudioBufferBaseSourceNode() {
27
+ if (onPositionChangedCallbackId_ != 0 &&
28
+ context_->audioEventHandlerRegistry_ != nullptr) {
29
+ context_->audioEventHandlerRegistry_->unregisterHandler(
30
+ "positionChanged", onPositionChangedCallbackId_);
31
+ onPositionChangedCallbackId_ = 0;
32
+ }
33
+ }
34
+
26
35
  std::shared_ptr<AudioParam> AudioBufferBaseSourceNode::getDetuneParam() const {
27
36
  return detuneParam_;
28
37
  }
@@ -42,13 +51,18 @@ void AudioBufferBaseSourceNode::setOnPositionChangedInterval(int interval) {
42
51
  context_->getSampleRate() * static_cast<float>(interval) / 1000);
43
52
  }
44
53
 
54
+ int AudioBufferBaseSourceNode::getOnPositionChangedInterval() {
55
+ return onPositionChangedInterval_;
56
+ }
57
+
45
58
  std::mutex &AudioBufferBaseSourceNode::getBufferLock() {
46
59
  return bufferLock_;
47
60
  }
48
61
 
49
62
  void AudioBufferBaseSourceNode::sendOnPositionChangedEvent() {
50
63
  if (onPositionChangedCallbackId_ != 0 &&
51
- onPositionChangedTime_ > onPositionChangedInterval_) {
64
+ onPositionChangedTime_ > onPositionChangedInterval_ &&
65
+ context_->audioEventHandlerRegistry_ != nullptr) {
52
66
  std::unordered_map<std::string, EventValue> body = {
53
67
  {"value", getCurrentPosition()}};
54
68
 
@@ -4,6 +4,7 @@
4
4
  #include <audioapi/libs/signalsmith-stretch/signalsmith-stretch.h>
5
5
 
6
6
  #include <memory>
7
+ #include <mutex>
7
8
 
8
9
  namespace audioapi {
9
10
 
@@ -13,12 +14,14 @@ class AudioParam;
13
14
  class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
14
15
  public:
15
16
  explicit AudioBufferBaseSourceNode(BaseAudioContext *context);
17
+ virtual ~AudioBufferBaseSourceNode();
16
18
 
17
- [[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
18
- [[nodiscard]] std::shared_ptr<AudioParam> getPlaybackRateParam() const;
19
+ [[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
20
+ [[nodiscard]] std::shared_ptr<AudioParam> getPlaybackRateParam() const;
19
21
 
20
- void setOnPositionChangedCallbackId(uint64_t callbackId);
21
- void setOnPositionChangedInterval(int interval);
22
+ void setOnPositionChangedCallbackId(uint64_t callbackId);
23
+ void setOnPositionChangedInterval(int interval);
24
+ [[nodiscard]] int getOnPositionChangedInterval();
22
25
 
23
26
  protected:
24
27
  std::mutex bufferLock_;
@@ -16,6 +16,15 @@ AudioScheduledSourceNode::AudioScheduledSourceNode(BaseAudioContext *context)
16
16
  numberOfInputs_ = 0;
17
17
  }
18
18
 
19
+ AudioScheduledSourceNode::~AudioScheduledSourceNode() {
20
+ if (onEndedCallbackId_ != 0 &&
21
+ context_->audioEventHandlerRegistry_ != nullptr) {
22
+ context_->audioEventHandlerRegistry_->unregisterHandler(
23
+ "ended", onEndedCallbackId_);
24
+ onEndedCallbackId_ = 0;
25
+ }
26
+ }
27
+
19
28
  void AudioScheduledSourceNode::start(double when) {
20
29
  playbackState_ = PlaybackState::SCHEDULED;
21
30
  startTime_ = when;
@@ -149,8 +158,10 @@ void AudioScheduledSourceNode::updatePlaybackInfo(
149
158
  void AudioScheduledSourceNode::disable() {
150
159
  AudioNode::disable();
151
160
 
152
- context_->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
153
- "ended", onEndedCallbackId_, {});
161
+ if (context_->audioEventHandlerRegistry_ != nullptr) {
162
+ context_->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
163
+ "ended", onEndedCallbackId_, {});
164
+ }
154
165
  }
155
166
 
156
167
  void AudioScheduledSourceNode::handleStopScheduled() {
@@ -27,6 +27,7 @@ class AudioScheduledSourceNode : public AudioNode {
27
27
  // FINISHED: The node has finished playing.
28
28
  enum class PlaybackState { UNSCHEDULED, SCHEDULED, PLAYING, STOP_SCHEDULED, FINISHED };
29
29
  explicit AudioScheduledSourceNode(BaseAudioContext *context);
30
+ virtual ~AudioScheduledSourceNode();
30
31
 
31
32
  void start(double when);
32
33
  virtual void stop(double when);
@@ -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