react-native-audio-api 0.11.0-nightly-568a154-20251222 → 0.11.0-nightly-9548557-20251223

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 (62) hide show
  1. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +2 -0
  2. package/common/cpp/audioapi/HostObjects/effects/DelayNodeHostObject.cpp +6 -2
  3. package/common/cpp/audioapi/core/AudioContext.cpp +15 -13
  4. package/common/cpp/audioapi/core/AudioContext.h +2 -1
  5. package/common/cpp/audioapi/core/AudioNode.cpp +39 -24
  6. package/common/cpp/audioapi/core/AudioNode.h +3 -3
  7. package/common/cpp/audioapi/core/AudioParam.cpp +9 -6
  8. package/common/cpp/audioapi/core/AudioParam.h +2 -2
  9. package/common/cpp/audioapi/core/BaseAudioContext.cpp +25 -21
  10. package/common/cpp/audioapi/core/BaseAudioContext.h +3 -1
  11. package/common/cpp/audioapi/core/analysis/AnalyserNode.cpp +8 -11
  12. package/common/cpp/audioapi/core/analysis/AnalyserNode.h +1 -1
  13. package/common/cpp/audioapi/core/destinations/AudioDestinationNode.cpp +9 -3
  14. package/common/cpp/audioapi/core/destinations/AudioDestinationNode.h +1 -1
  15. package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +18 -9
  16. package/common/cpp/audioapi/core/effects/BiquadFilterNode.h +1 -1
  17. package/common/cpp/audioapi/core/effects/ConvolverNode.cpp +4 -4
  18. package/common/cpp/audioapi/core/effects/ConvolverNode.h +1 -1
  19. package/common/cpp/audioapi/core/effects/DelayNode.cpp +20 -11
  20. package/common/cpp/audioapi/core/effects/DelayNode.h +1 -1
  21. package/common/cpp/audioapi/core/effects/GainNode.cpp +12 -4
  22. package/common/cpp/audioapi/core/effects/GainNode.h +1 -1
  23. package/common/cpp/audioapi/core/effects/IIRFilterNode.cpp +6 -3
  24. package/common/cpp/audioapi/core/effects/IIRFilterNode.h +1 -1
  25. package/common/cpp/audioapi/core/effects/StereoPannerNode.cpp +7 -4
  26. package/common/cpp/audioapi/core/effects/StereoPannerNode.h +1 -1
  27. package/common/cpp/audioapi/core/effects/WorkletNode.cpp +3 -3
  28. package/common/cpp/audioapi/core/effects/WorkletNode.h +2 -2
  29. package/common/cpp/audioapi/core/effects/WorkletProcessingNode.cpp +7 -4
  30. package/common/cpp/audioapi/core/effects/WorkletProcessingNode.h +6 -2
  31. package/common/cpp/audioapi/core/sources/AudioBuffer.cpp +2 -3
  32. package/common/cpp/audioapi/core/sources/AudioBuffer.h +1 -1
  33. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +59 -25
  34. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +4 -2
  35. package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +18 -11
  36. package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h +3 -1
  37. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +37 -21
  38. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +3 -3
  39. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +11 -11
  40. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +4 -2
  41. package/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp +16 -8
  42. package/common/cpp/audioapi/core/sources/ConstantSourceNode.h +1 -1
  43. package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +30 -18
  44. package/common/cpp/audioapi/core/sources/OscillatorNode.h +1 -1
  45. package/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp +4 -4
  46. package/common/cpp/audioapi/core/sources/RecorderAdapterNode.h +1 -1
  47. package/common/cpp/audioapi/core/sources/StreamerNode.cpp +24 -10
  48. package/common/cpp/audioapi/core/sources/StreamerNode.h +4 -3
  49. package/common/cpp/audioapi/core/sources/WorkletSourceNode.cpp +11 -4
  50. package/common/cpp/audioapi/core/sources/WorkletSourceNode.h +6 -2
  51. package/common/cpp/test/RunTests.sh +1 -1
  52. package/common/cpp/test/src/AudioParamTest.cpp +10 -10
  53. package/common/cpp/test/src/AudioScheduledSourceTest.cpp +31 -15
  54. package/common/cpp/test/src/ConstantSourceTest.cpp +16 -14
  55. package/common/cpp/test/src/DelayTest.cpp +14 -13
  56. package/common/cpp/test/src/GainTest.cpp +10 -9
  57. package/common/cpp/test/src/IIRFilterTest.cpp +4 -4
  58. package/common/cpp/test/src/OscillatorTest.cpp +2 -2
  59. package/common/cpp/test/src/StereoPannerTest.cpp +14 -12
  60. package/common/cpp/test/src/biquad/BiquadFilterTest.cpp +25 -25
  61. package/common/cpp/test/src/biquad/BiquadFilterTest.h +3 -5
  62. package/package.json +1 -1
@@ -12,15 +12,16 @@
12
12
 
13
13
  namespace audioapi {
14
14
 
15
- AudioBufferSourceNode::AudioBufferSourceNode(BaseAudioContext *context, bool pitchCorrection)
15
+ AudioBufferSourceNode::AudioBufferSourceNode(
16
+ std::shared_ptr<BaseAudioContext> context,
17
+ bool pitchCorrection)
16
18
  : AudioBufferBaseSourceNode(context, pitchCorrection),
17
19
  loop_(false),
18
20
  loopSkip_(false),
19
21
  loopStart_(0),
20
- loopEnd_(0) {
21
- buffer_ = std::shared_ptr<AudioBuffer>(nullptr);
22
- alignedBus_ = std::shared_ptr<AudioBus>(nullptr);
23
-
22
+ loopEnd_(0),
23
+ buffer_(nullptr),
24
+ alignedBus_(nullptr) {
24
25
  isInitialized_ = true;
25
26
  }
26
27
 
@@ -61,7 +62,9 @@ void AudioBufferSourceNode::setLoopSkip(bool loopSkip) {
61
62
 
62
63
  void AudioBufferSourceNode::setLoopStart(double loopStart) {
63
64
  if (loopSkip_) {
64
- vReadIndex_ = loopStart * context_->getSampleRate();
65
+ if (std::shared_ptr<BaseAudioContext> context = context_.lock()) {
66
+ vReadIndex_ = loopStart * context->getSampleRate();
67
+ }
65
68
  }
66
69
  loopStart_ = loopStart;
67
70
  }
@@ -72,8 +75,9 @@ void AudioBufferSourceNode::setLoopEnd(double loopEnd) {
72
75
 
73
76
  void AudioBufferSourceNode::setBuffer(const std::shared_ptr<AudioBuffer> &buffer) {
74
77
  Locker locker(getBufferLock());
78
+ std::shared_ptr<BaseAudioContext> context = context_.lock();
75
79
 
76
- if (!buffer) {
80
+ if (buffer == nullptr || context == nullptr) {
77
81
  buffer_ = std::shared_ptr<AudioBuffer>(nullptr);
78
82
  alignedBus_ = std::shared_ptr<AudioBus>(nullptr);
79
83
  loopEnd_ = 0;
@@ -87,7 +91,7 @@ void AudioBufferSourceNode::setBuffer(const std::shared_ptr<AudioBuffer> &buffer
87
91
 
88
92
  if (pitchCorrection_) {
89
93
  int extraTailFrames =
90
- static_cast<int>((getInputLatency() + getOutputLatency()) * context_->getSampleRate());
94
+ static_cast<int>((getInputLatency() + getOutputLatency()) * context->getSampleRate());
91
95
  size_t totalSize = buffer_->getLength() + extraTailFrames;
92
96
 
93
97
  alignedBus_ = std::make_shared<AudioBus>(totalSize, channelCount_, buffer_->getSampleRate());
@@ -97,11 +101,10 @@ void AudioBufferSourceNode::setBuffer(const std::shared_ptr<AudioBuffer> &buffer
97
101
  } else {
98
102
  alignedBus_ = std::make_shared<AudioBus>(*buffer_->bus_);
99
103
  }
100
-
101
104
  audioBus_ =
102
- std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, channelCount_, context_->getSampleRate());
103
- playbackRateBus_ =
104
- std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE * 3, channelCount_, context_->getSampleRate());
105
+ std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, channelCount_, context->getSampleRate());
106
+ playbackRateBus_ = std::make_shared<AudioBus>(
107
+ RENDER_QUANTUM_SIZE * 3, channelCount_, context->getSampleRate());
105
108
 
106
109
  loopEnd_ = buffer_->getDuration();
107
110
  }
@@ -189,8 +192,15 @@ void AudioBufferSourceNode::processWithoutInterpolation(
189
192
  auto readIndex = static_cast<size_t>(vReadIndex_);
190
193
  size_t writeIndex = startOffset;
191
194
 
192
- auto frameStart = static_cast<size_t>(getVirtualStartFrame());
193
- auto frameEnd = static_cast<size_t>(getVirtualEndFrame());
195
+ size_t frameStart;
196
+ size_t frameEnd;
197
+ if (std::shared_ptr<BaseAudioContext> context = context_.lock()) {
198
+ frameStart = static_cast<size_t>(getVirtualStartFrame(context->getSampleRate()));
199
+ frameEnd = static_cast<size_t>(getVirtualEndFrame(context->getSampleRate()));
200
+ } else {
201
+ processingBus->zero();
202
+ return;
203
+ }
194
204
  size_t frameDelta = frameEnd - frameStart;
195
205
 
196
206
  size_t framesLeft = offsetLength;
@@ -257,8 +267,15 @@ void AudioBufferSourceNode::processWithInterpolation(
257
267
 
258
268
  size_t writeIndex = startOffset;
259
269
 
260
- auto vFrameStart = getVirtualStartFrame();
261
- auto vFrameEnd = getVirtualEndFrame();
270
+ double vFrameStart;
271
+ double vFrameEnd;
272
+ if (std::shared_ptr<BaseAudioContext> context = context_.lock()) {
273
+ vFrameStart = getVirtualStartFrame(context->getSampleRate());
274
+ vFrameEnd = getVirtualEndFrame(context->getSampleRate());
275
+ } else {
276
+ processingBus->zero();
277
+ return;
278
+ }
262
279
  auto vFrameDelta = vFrameEnd - vFrameStart;
263
280
 
264
281
  auto frameStart = static_cast<size_t>(vFrameStart);
@@ -305,15 +322,14 @@ void AudioBufferSourceNode::processWithInterpolation(
305
322
  }
306
323
  }
307
324
 
308
- double AudioBufferSourceNode::getVirtualStartFrame() {
309
- auto loopStartFrame = loopStart_ * context_->getSampleRate();
310
-
325
+ double AudioBufferSourceNode::getVirtualStartFrame(float sampleRate) {
326
+ auto loopStartFrame = loopStart_ * sampleRate;
311
327
  return loop_ && loopStartFrame >= 0 && loopStart_ < loopEnd_ ? loopStartFrame : 0.0;
312
328
  }
313
329
 
314
- double AudioBufferSourceNode::getVirtualEndFrame() {
330
+ double AudioBufferSourceNode::getVirtualEndFrame(float sampleRate) {
315
331
  auto inputBufferLength = static_cast<double>(alignedBus_->getSize());
316
- auto loopEndFrame = loopEnd_ * context_->getSampleRate();
332
+ auto loopEndFrame = loopEnd_ * sampleRate;
317
333
 
318
334
  return loop_ && loopEndFrame > 0 && loopStart_ < loopEnd_
319
335
  ? std::min(loopEndFrame, inputBufferLength)
@@ -16,7 +16,7 @@ class AudioParam;
16
16
 
17
17
  class AudioBufferSourceNode : public AudioBufferBaseSourceNode {
18
18
  public:
19
- explicit AudioBufferSourceNode(BaseAudioContext *context, bool pitchCorrection);
19
+ explicit AudioBufferSourceNode(std::shared_ptr<BaseAudioContext> context, bool pitchCorrection);
20
20
  ~AudioBufferSourceNode() override;
21
21
 
22
22
  [[nodiscard]] bool getLoop() const;
@@ -69,8 +69,8 @@ class AudioBufferSourceNode : public AudioBufferBaseSourceNode {
69
69
  size_t offsetLength,
70
70
  float playbackRate) override;
71
71
 
72
- double getVirtualStartFrame();
73
- double getVirtualEndFrame();
72
+ double getVirtualStartFrame(float sampleRate);
73
+ double getVirtualEndFrame(float sampleRate);
74
74
  };
75
75
 
76
76
  } // namespace audioapi
@@ -16,19 +16,21 @@
16
16
 
17
17
  namespace audioapi {
18
18
 
19
- AudioScheduledSourceNode::AudioScheduledSourceNode(BaseAudioContext *context)
19
+ AudioScheduledSourceNode::AudioScheduledSourceNode(std::shared_ptr<BaseAudioContext> context)
20
20
  : AudioNode(context),
21
21
  startTime_(-1.0),
22
22
  stopTime_(-1.0),
23
- playbackState_(PlaybackState::UNSCHEDULED) {
23
+ playbackState_(PlaybackState::UNSCHEDULED),
24
+ audioEventHandlerRegistry_(context->audioEventHandlerRegistry_) {
24
25
  numberOfInputs_ = 0;
25
- audioEventHandlerRegistry_ = context_->audioEventHandlerRegistry_;
26
26
  }
27
27
 
28
28
  void AudioScheduledSourceNode::start(double when) {
29
29
  #if !RN_AUDIO_API_TEST
30
- if (auto context = dynamic_cast<AudioContext *>(context_)) {
31
- context->start();
30
+ if (std::shared_ptr<BaseAudioContext> context = context_.lock()) {
31
+ if (auto audioContext = dynamic_cast<AudioContext *>(context.get())) {
32
+ audioContext->start();
33
+ }
32
34
  }
33
35
  #endif // RN_AUDIO_API_TEST
34
36
 
@@ -72,18 +74,16 @@ void AudioScheduledSourceNode::updatePlaybackInfo(
72
74
  const std::shared_ptr<AudioBus> &processingBus,
73
75
  int framesToProcess,
74
76
  size_t &startOffset,
75
- size_t &nonSilentFramesToProcess) {
77
+ size_t &nonSilentFramesToProcess,
78
+ float sampleRate,
79
+ size_t currentSampleFrame) {
76
80
  if (!isInitialized_) {
77
81
  startOffset = 0;
78
82
  nonSilentFramesToProcess = 0;
79
83
  return;
80
84
  }
81
85
 
82
- assert(context_ != nullptr);
83
-
84
- auto sampleRate = context_->getSampleRate();
85
-
86
- size_t firstFrame = context_->getCurrentSampleFrame();
86
+ auto firstFrame = currentSampleFrame;
87
87
  size_t lastFrame = firstFrame + framesToProcess - 1;
88
88
 
89
89
  size_t startFrame = std::max(dsp::timeToSampleFrame(startTime_, sampleRate), firstFrame);
@@ -26,7 +26,7 @@ class AudioScheduledSourceNode : public AudioNode {
26
26
  // STOP_SCHEDULED: The node is scheduled to stop at a specific time, but is still playing.
27
27
  // FINISHED: The node has finished playing.
28
28
  enum class PlaybackState { UNSCHEDULED, SCHEDULED, PLAYING, STOP_SCHEDULED, FINISHED };
29
- explicit AudioScheduledSourceNode(BaseAudioContext *context);
29
+ explicit AudioScheduledSourceNode(std::shared_ptr<BaseAudioContext> context);
30
30
 
31
31
  virtual void start(double when);
32
32
  virtual void stop(double when);
@@ -54,7 +54,9 @@ class AudioScheduledSourceNode : public AudioNode {
54
54
  const std::shared_ptr<AudioBus> &processingBus,
55
55
  int framesToProcess,
56
56
  size_t &startOffset,
57
- size_t &nonSilentFramesToProcess);
57
+ size_t &nonSilentFramesToProcess,
58
+ float sampleRate,
59
+ size_t currentSampleFrame);
58
60
 
59
61
  void handleStopScheduled();
60
62
  };
@@ -6,10 +6,14 @@
6
6
  #include <memory>
7
7
 
8
8
  namespace audioapi {
9
- ConstantSourceNode::ConstantSourceNode(BaseAudioContext *context)
10
- : AudioScheduledSourceNode(context) {
11
- offsetParam_ = std::make_shared<AudioParam>(
12
- 1.0, MOST_NEGATIVE_SINGLE_FLOAT, MOST_POSITIVE_SINGLE_FLOAT, context);
9
+ ConstantSourceNode::ConstantSourceNode(std::shared_ptr<BaseAudioContext> context)
10
+ : AudioScheduledSourceNode(context),
11
+ offsetParam_(
12
+ std::make_shared<AudioParam>(
13
+ 1.0,
14
+ MOST_NEGATIVE_SINGLE_FLOAT,
15
+ MOST_POSITIVE_SINGLE_FLOAT,
16
+ context)) {
13
17
  isInitialized_ = true;
14
18
  }
15
19
 
@@ -23,15 +27,19 @@ std::shared_ptr<AudioBus> ConstantSourceNode::processNode(
23
27
  size_t startOffset = 0;
24
28
  size_t offsetLength = 0;
25
29
 
26
- updatePlaybackInfo(processingBus, framesToProcess, startOffset, offsetLength);
27
-
28
- if (!isPlaying() && !isStopScheduled()) {
30
+ std::shared_ptr<BaseAudioContext> context = context_.lock();
31
+ if (context == nullptr) {
29
32
  processingBus->zero();
30
33
  return processingBus;
31
34
  }
32
35
 
33
- auto offsetBus = offsetParam_->processARateParam(framesToProcess, context_->getCurrentTime());
36
+ updatePlaybackInfo(processingBus, framesToProcess, startOffset, offsetLength, context->getSampleRate(), context->getCurrentSampleFrame());
34
37
 
38
+ if (!isPlaying() && !isStopScheduled()) {
39
+ processingBus->zero();
40
+ return processingBus;
41
+ }
42
+ auto offsetBus = offsetParam_->processARateParam(framesToProcess, context->getCurrentTime());
35
43
  auto offsetChannelData = offsetBus->getChannel(0)->getData();
36
44
 
37
45
  for (int channel = 0; channel < processingBus->getNumberOfChannels(); ++channel) {
@@ -13,7 +13,7 @@ class AudioBus;
13
13
 
14
14
  class ConstantSourceNode : public AudioScheduledSourceNode {
15
15
  public:
16
- explicit ConstantSourceNode(BaseAudioContext *context);
16
+ explicit ConstantSourceNode(std::shared_ptr<BaseAudioContext> context);
17
17
 
18
18
  [[nodiscard]] std::shared_ptr<AudioParam> getOffsetParam() const;
19
19
 
@@ -8,19 +8,23 @@
8
8
 
9
9
  namespace audioapi {
10
10
 
11
- OscillatorNode::OscillatorNode(BaseAudioContext *context) : AudioScheduledSourceNode(context) {
12
- frequencyParam_ = std::make_shared<AudioParam>(
13
- 444.0, -context_->getNyquistFrequency(), context_->getNyquistFrequency(), context);
14
- detuneParam_ = std::make_shared<AudioParam>(
15
- 0.0,
16
- -1200 * LOG2_MOST_POSITIVE_SINGLE_FLOAT,
17
- 1200 * LOG2_MOST_POSITIVE_SINGLE_FLOAT,
18
- context);
19
- type_ = OscillatorType::SINE;
20
- periodicWave_ = context_->getBasicWaveForm(type_);
21
-
22
- audioBus_ = std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, 1, context_->getSampleRate());
23
-
11
+ OscillatorNode::OscillatorNode(std::shared_ptr<BaseAudioContext> context)
12
+ : AudioScheduledSourceNode(context),
13
+ frequencyParam_(
14
+ std::make_shared<AudioParam>(
15
+ 444.0,
16
+ -context->getNyquistFrequency(),
17
+ context->getNyquistFrequency(),
18
+ context)),
19
+ detuneParam_(
20
+ std::make_shared<AudioParam>(
21
+ 0.0,
22
+ -1200 * LOG2_MOST_POSITIVE_SINGLE_FLOAT,
23
+ 1200 * LOG2_MOST_POSITIVE_SINGLE_FLOAT,
24
+ context)),
25
+ type_(OscillatorType::SINE),
26
+ periodicWave_(context->getBasicWaveForm(type_)) {
27
+ audioBus_ = std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, 1, context->getSampleRate());
24
28
  isInitialized_ = true;
25
29
  }
26
30
 
@@ -37,8 +41,10 @@ std::string OscillatorNode::getType() {
37
41
  }
38
42
 
39
43
  void OscillatorNode::setType(const std::string &type) {
40
- type_ = OscillatorNode::fromString(type);
41
- periodicWave_ = context_->getBasicWaveForm(type_);
44
+ if (std::shared_ptr<BaseAudioContext> context = context_.lock()) {
45
+ type_ = OscillatorNode::fromString(type);
46
+ periodicWave_ = context->getBasicWaveForm(type_);
47
+ }
42
48
  }
43
49
 
44
50
  void OscillatorNode::setPeriodicWave(const std::shared_ptr<PeriodicWave> &periodicWave) {
@@ -52,15 +58,21 @@ std::shared_ptr<AudioBus> OscillatorNode::processNode(
52
58
  size_t startOffset = 0;
53
59
  size_t offsetLength = 0;
54
60
 
55
- updatePlaybackInfo(processingBus, framesToProcess, startOffset, offsetLength);
61
+ std::shared_ptr<BaseAudioContext> context = context_.lock();
62
+ if (context == nullptr) {
63
+ processingBus->zero();
64
+ return processingBus;
65
+ }
66
+
67
+ updatePlaybackInfo(processingBus, framesToProcess, startOffset, offsetLength, context->getSampleRate(), context->getCurrentSampleFrame());
56
68
 
57
69
  if (!isPlaying() && !isStopScheduled()) {
58
70
  processingBus->zero();
59
71
  return processingBus;
60
72
  }
61
73
 
62
- auto time = context_->getCurrentTime() +
63
- static_cast<double>(startOffset) * 1.0 / context_->getSampleRate();
74
+ auto time =
75
+ context->getCurrentTime() + static_cast<double>(startOffset) * 1.0 / context->getSampleRate();
64
76
  auto detuneParamValues = detuneParam_->processARateParam(framesToProcess, time);
65
77
  auto frequencyParamValues = frequencyParam_->processARateParam(framesToProcess, time);
66
78
 
@@ -16,7 +16,7 @@ class AudioBus;
16
16
 
17
17
  class OscillatorNode : public AudioScheduledSourceNode {
18
18
  public:
19
- explicit OscillatorNode(BaseAudioContext *context);
19
+ explicit OscillatorNode(std::shared_ptr<BaseAudioContext> context);
20
20
 
21
21
  [[nodiscard]] std::shared_ptr<AudioParam> getFrequencyParam() const;
22
22
  [[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
@@ -9,8 +9,7 @@
9
9
 
10
10
  namespace audioapi {
11
11
 
12
- RecorderAdapterNode::RecorderAdapterNode(BaseAudioContext *context) noexcept(
13
- std::is_nothrow_constructible<AudioNode, BaseAudioContext *>::value)
12
+ RecorderAdapterNode::RecorderAdapterNode(std::shared_ptr<BaseAudioContext> context)
14
13
  : AudioNode(context) {
15
14
  // It should be marked as initialized only after it is connected to the
16
15
  // recorder. Internall buffer size is based on the recorder's buffer length.
@@ -18,7 +17,8 @@ RecorderAdapterNode::RecorderAdapterNode(BaseAudioContext *context) noexcept(
18
17
  }
19
18
 
20
19
  void RecorderAdapterNode::init(size_t bufferSize, int channelCount) {
21
- if (isInitialized_) {
20
+ std::shared_ptr<BaseAudioContext> context = context_.lock();
21
+ if (isInitialized_ || context == nullptr) {
22
22
  return;
23
23
  }
24
24
 
@@ -42,7 +42,7 @@ void RecorderAdapterNode::init(size_t bufferSize, int channelCount) {
42
42
  // context output and not enforcing anything on the system output/input configuration.
43
43
  // A lot of words for a couple of lines of implementation :shrug:
44
44
  adapterOutputBus_ =
45
- std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, channelCount_, context_->getSampleRate());
45
+ std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, channelCount_, context->getSampleRate());
46
46
  isInitialized_ = true;
47
47
  }
48
48
 
@@ -19,7 +19,7 @@ class AudioBus;
19
19
  /// @note it will push silence if it is not connected to any Recorder
20
20
  class RecorderAdapterNode : public AudioNode {
21
21
  public:
22
- explicit RecorderAdapterNode(BaseAudioContext *context);
22
+ explicit RecorderAdapterNode(std::shared_ptr<BaseAudioContext> context);
23
23
 
24
24
  /// @brief Initialize the RecorderAdapterNode with a buffer size and channel count.
25
25
  /// @note This method should be called ONLY ONCE when the buffer size is known.
@@ -22,7 +22,7 @@
22
22
 
23
23
  namespace audioapi {
24
24
  #if !RN_AUDIO_API_FFMPEG_DISABLED
25
- StreamerNode::StreamerNode(BaseAudioContext *context)
25
+ StreamerNode::StreamerNode(std::shared_ptr<BaseAudioContext> context)
26
26
  : AudioScheduledSourceNode(context),
27
27
  fmtCtx_(nullptr),
28
28
  codecCtx_(nullptr),
@@ -37,7 +37,7 @@ StreamerNode::StreamerNode(BaseAudioContext *context)
37
37
  maxResampledSamples_(0),
38
38
  processedSamples_(0) {}
39
39
  #else
40
- StreamerNode::StreamerNode(BaseAudioContext *context) : AudioScheduledSourceNode(context) {}
40
+ StreamerNode::StreamerNode(std::shared_ptr<BaseAudioContext> context) : AudioScheduledSourceNode(context) {}
41
41
  #endif // RN_AUDIO_API_FFMPEG_DISABLED
42
42
 
43
43
  StreamerNode::~StreamerNode() {
@@ -48,6 +48,11 @@ StreamerNode::~StreamerNode() {
48
48
 
49
49
  bool StreamerNode::initialize(const std::string &input_url) {
50
50
  #if !RN_AUDIO_API_FFMPEG_DISABLED
51
+ std::shared_ptr<BaseAudioContext> context = context_.lock();
52
+ if (context == nullptr) {
53
+ return false;
54
+ }
55
+
51
56
  if (isInitialized_) {
52
57
  cleanup();
53
58
  }
@@ -58,7 +63,7 @@ bool StreamerNode::initialize(const std::string &input_url) {
58
63
  return false;
59
64
  }
60
65
 
61
- if (!findAudioStream() || !setupDecoder() || !setupResampler()) {
66
+ if (!findAudioStream() || !setupDecoder() || !setupResampler(context->getSampleRate())) {
62
67
  if (VERBOSE)
63
68
  printf("Failed to find/setup audio stream\n");
64
69
  cleanup();
@@ -77,7 +82,7 @@ bool StreamerNode::initialize(const std::string &input_url) {
77
82
 
78
83
  channelCount_ = codecpar_->ch_layout.nb_channels;
79
84
  audioBus_ =
80
- std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, channelCount_, context_->getSampleRate());
85
+ std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE, channelCount_, context->getSampleRate());
81
86
 
82
87
  auto [sender, receiver] = channels::spsc::channel<
83
88
  StreamingData,
@@ -100,7 +105,12 @@ std::shared_ptr<AudioBus> StreamerNode::processNode(
100
105
  #if !RN_AUDIO_API_FFMPEG_DISABLED
101
106
  size_t startOffset = 0;
102
107
  size_t offsetLength = 0;
103
- updatePlaybackInfo(processingBus, framesToProcess, startOffset, offsetLength);
108
+ std::shared_ptr<BaseAudioContext> context = context_.lock();
109
+ if (context == nullptr) {
110
+ processingBus->zero();
111
+ return processingBus;
112
+ }
113
+ updatePlaybackInfo(processingBus, framesToProcess, startOffset, offsetLength, context->getSampleRate(), context->getCurrentSampleFrame());
104
114
  isNodeFinished_.store(isFinished(), std::memory_order_release);
105
115
 
106
116
  if (!isPlaying() && !isStopScheduled()) {
@@ -146,7 +156,7 @@ std::shared_ptr<AudioBus> StreamerNode::processNode(
146
156
  }
147
157
 
148
158
  #if !RN_AUDIO_API_FFMPEG_DISABLED
149
- bool StreamerNode::setupResampler() {
159
+ bool StreamerNode::setupResampler(float outSampleRate) {
150
160
  // Allocate resampler context
151
161
  swrCtx_ = swr_alloc();
152
162
  if (swrCtx_ == nullptr) {
@@ -160,7 +170,7 @@ bool StreamerNode::setupResampler() {
160
170
 
161
171
  // Set output parameters (float)
162
172
  av_opt_set_chlayout(swrCtx_, "out_chlayout", &codecCtx_->ch_layout, 0);
163
- av_opt_set_int(swrCtx_, "out_sample_rate", context_->getSampleRate(), 0);
173
+ av_opt_set_int(swrCtx_, "out_sample_rate", outSampleRate, 0);
164
174
  av_opt_set_sample_fmt(swrCtx_, "out_sample_fmt", AV_SAMPLE_FMT_FLTP, 0);
165
175
 
166
176
  // Initialize the resampler
@@ -193,7 +203,11 @@ void StreamerNode::streamAudio() {
193
203
  if (avcodec_receive_frame(codecCtx_, frame_) != 0) {
194
204
  return;
195
205
  }
196
- if (!processFrameWithResampler(frame_)) {
206
+ std::shared_ptr<BaseAudioContext> context = context_.lock();
207
+ if (context == nullptr) {
208
+ return;
209
+ }
210
+ if (!processFrameWithResampler(frame_, context)) {
197
211
  return;
198
212
  }
199
213
  }
@@ -201,7 +215,7 @@ void StreamerNode::streamAudio() {
201
215
  }
202
216
  }
203
217
 
204
- bool StreamerNode::processFrameWithResampler(AVFrame *frame) {
218
+ bool StreamerNode::processFrameWithResampler(AVFrame *frame, std::shared_ptr<BaseAudioContext> context) {
205
219
  // Check if we need to reallocate the resampled buffer
206
220
  int out_samples = swr_get_out_samples(swrCtx_, frame->nb_samples);
207
221
  if (out_samples > maxResampledSamples_) {
@@ -241,7 +255,7 @@ bool StreamerNode::processFrameWithResampler(AVFrame *frame) {
241
255
  auto bus = AudioBus(
242
256
  static_cast<size_t>(converted_samples),
243
257
  codecCtx_->ch_layout.nb_channels,
244
- context_->getSampleRate());
258
+ context->getSampleRate());
245
259
  for (int ch = 0; ch < codecCtx_->ch_layout.nb_channels; ch++) {
246
260
  auto *src = reinterpret_cast<float *>(resampledData_[ch]);
247
261
  float *dst = bus.getChannel(ch)->getData();
@@ -62,7 +62,7 @@ class AudioBus;
62
62
 
63
63
  class StreamerNode : public AudioScheduledSourceNode {
64
64
  public:
65
- explicit StreamerNode(BaseAudioContext *context);
65
+ explicit StreamerNode(std::shared_ptr<BaseAudioContext> context);
66
66
  ~StreamerNode() override;
67
67
 
68
68
  /**
@@ -106,16 +106,17 @@ class StreamerNode : public AudioScheduledSourceNode {
106
106
 
107
107
  /**
108
108
  * @brief Setting up the resampler
109
+ * @param outSampleRate Sample rate for the output audio
109
110
  * @return true if successful, false otherwise
110
111
  */
111
- bool setupResampler();
112
+ bool setupResampler(float outSampleRate);
112
113
 
113
114
  /**
114
115
  * @brief Resample the audio frame, change its sample format and channel layout
115
116
  * @param frame The AVFrame to resample
116
117
  * @return true if successful, false otherwise
117
118
  */
118
- bool processFrameWithResampler(AVFrame *frame);
119
+ bool processFrameWithResampler(AVFrame *frame, std::shared_ptr<BaseAudioContext> context);
119
120
 
120
121
  /**
121
122
  * @brief Thread function to continuously read and process audio frames
@@ -5,7 +5,9 @@
5
5
 
6
6
  namespace audioapi {
7
7
 
8
- WorkletSourceNode::WorkletSourceNode(BaseAudioContext *context, WorkletsRunner &&workletRunner)
8
+ WorkletSourceNode::WorkletSourceNode(
9
+ std::shared_ptr<BaseAudioContext> context,
10
+ WorkletsRunner &&workletRunner)
9
11
  : AudioScheduledSourceNode(context), workletRunner_(std::move(workletRunner)) {
10
12
  isInitialized_ = true;
11
13
 
@@ -29,7 +31,12 @@ std::shared_ptr<AudioBus> WorkletSourceNode::processNode(
29
31
  size_t startOffset = 0;
30
32
  size_t nonSilentFramesToProcess = framesToProcess;
31
33
 
32
- updatePlaybackInfo(processingBus, framesToProcess, startOffset, nonSilentFramesToProcess);
34
+ std::shared_ptr<BaseAudioContext> context = context_.lock();
35
+ if (context == nullptr) {
36
+ processingBus->zero();
37
+ return processingBus;
38
+ }
39
+ updatePlaybackInfo(processingBus, framesToProcess, startOffset, nonSilentFramesToProcess, context->getSampleRate(), context->getCurrentSampleFrame());
33
40
 
34
41
  if (nonSilentFramesToProcess == 0) {
35
42
  processingBus->zero();
@@ -39,7 +46,7 @@ std::shared_ptr<AudioBus> WorkletSourceNode::processNode(
39
46
  size_t outputChannelCount = processingBus->getNumberOfChannels();
40
47
 
41
48
  auto result = workletRunner_.executeOnRuntimeSync(
42
- [this, nonSilentFramesToProcess, startOffset](jsi::Runtime &rt) {
49
+ [this, nonSilentFramesToProcess, startOffset, time = context->getCurrentTime()](jsi::Runtime &rt) {
43
50
  auto jsiArray = jsi::Array(rt, this->outputBuffsHandles_.size());
44
51
  for (size_t i = 0; i < this->outputBuffsHandles_.size(); ++i) {
45
52
  auto arrayBuffer = jsi::ArrayBuffer(rt, this->outputBuffsHandles_[i]);
@@ -52,7 +59,7 @@ std::shared_ptr<AudioBus> WorkletSourceNode::processNode(
52
59
  return workletRunner_.callUnsafe(
53
60
  jsiArray,
54
61
  jsi::Value(rt, static_cast<int>(nonSilentFramesToProcess)),
55
- jsi::Value(rt, this->context_->getCurrentTime()),
62
+ jsi::Value(rt, time),
56
63
  jsi::Value(rt, static_cast<int>(startOffset)));
57
64
  });
58
65
 
@@ -16,7 +16,9 @@ namespace audioapi {
16
16
  #if RN_AUDIO_API_TEST
17
17
  class WorkletSourceNode : public AudioScheduledSourceNode {
18
18
  public:
19
- explicit WorkletSourceNode(BaseAudioContext *context, WorkletsRunner &&workletRunner)
19
+ explicit WorkletSourceNode(
20
+ std::shared_ptr<BaseAudioContext> context,
21
+ WorkletsRunner &&workletRunner)
20
22
  : AudioScheduledSourceNode(context) {}
21
23
 
22
24
  protected:
@@ -30,7 +32,9 @@ class WorkletSourceNode : public AudioScheduledSourceNode {
30
32
 
31
33
  class WorkletSourceNode : public AudioScheduledSourceNode {
32
34
  public:
33
- explicit WorkletSourceNode(BaseAudioContext *context, WorkletsRunner &&workletRunner);
35
+ explicit WorkletSourceNode(
36
+ std::shared_ptr<BaseAudioContext> context,
37
+ WorkletsRunner &&workletRunner);
34
38
 
35
39
  protected:
36
40
  std::shared_ptr<AudioBus> processNode(
@@ -15,7 +15,7 @@ cmake -S . -B build -Wno-dev
15
15
 
16
16
  cd build
17
17
  make -j10
18
- ./tests
18
+ ./tests --gtest_print_time=1
19
19
  cd ..
20
20
 
21
21
  rm -rf build/