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.
- package/common/cpp/audioapi/AudioAPIModuleInstaller.h +2 -0
- package/common/cpp/audioapi/HostObjects/effects/DelayNodeHostObject.cpp +6 -2
- package/common/cpp/audioapi/core/AudioContext.cpp +15 -13
- package/common/cpp/audioapi/core/AudioContext.h +2 -1
- package/common/cpp/audioapi/core/AudioNode.cpp +39 -24
- package/common/cpp/audioapi/core/AudioNode.h +3 -3
- package/common/cpp/audioapi/core/AudioParam.cpp +9 -6
- package/common/cpp/audioapi/core/AudioParam.h +2 -2
- package/common/cpp/audioapi/core/BaseAudioContext.cpp +25 -21
- package/common/cpp/audioapi/core/BaseAudioContext.h +3 -1
- package/common/cpp/audioapi/core/analysis/AnalyserNode.cpp +8 -11
- package/common/cpp/audioapi/core/analysis/AnalyserNode.h +1 -1
- package/common/cpp/audioapi/core/destinations/AudioDestinationNode.cpp +9 -3
- package/common/cpp/audioapi/core/destinations/AudioDestinationNode.h +1 -1
- package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +18 -9
- package/common/cpp/audioapi/core/effects/BiquadFilterNode.h +1 -1
- package/common/cpp/audioapi/core/effects/ConvolverNode.cpp +4 -4
- package/common/cpp/audioapi/core/effects/ConvolverNode.h +1 -1
- package/common/cpp/audioapi/core/effects/DelayNode.cpp +20 -11
- package/common/cpp/audioapi/core/effects/DelayNode.h +1 -1
- package/common/cpp/audioapi/core/effects/GainNode.cpp +12 -4
- package/common/cpp/audioapi/core/effects/GainNode.h +1 -1
- package/common/cpp/audioapi/core/effects/IIRFilterNode.cpp +6 -3
- package/common/cpp/audioapi/core/effects/IIRFilterNode.h +1 -1
- package/common/cpp/audioapi/core/effects/StereoPannerNode.cpp +7 -4
- package/common/cpp/audioapi/core/effects/StereoPannerNode.h +1 -1
- package/common/cpp/audioapi/core/effects/WorkletNode.cpp +3 -3
- package/common/cpp/audioapi/core/effects/WorkletNode.h +2 -2
- package/common/cpp/audioapi/core/effects/WorkletProcessingNode.cpp +7 -4
- package/common/cpp/audioapi/core/effects/WorkletProcessingNode.h +6 -2
- package/common/cpp/audioapi/core/sources/AudioBuffer.cpp +2 -3
- package/common/cpp/audioapi/core/sources/AudioBuffer.h +1 -1
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +59 -25
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +4 -2
- package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +18 -11
- package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h +3 -1
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +37 -21
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +3 -3
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +11 -11
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +4 -2
- package/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp +16 -8
- package/common/cpp/audioapi/core/sources/ConstantSourceNode.h +1 -1
- package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +30 -18
- package/common/cpp/audioapi/core/sources/OscillatorNode.h +1 -1
- package/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp +4 -4
- package/common/cpp/audioapi/core/sources/RecorderAdapterNode.h +1 -1
- package/common/cpp/audioapi/core/sources/StreamerNode.cpp +24 -10
- package/common/cpp/audioapi/core/sources/StreamerNode.h +4 -3
- package/common/cpp/audioapi/core/sources/WorkletSourceNode.cpp +11 -4
- package/common/cpp/audioapi/core/sources/WorkletSourceNode.h +6 -2
- package/common/cpp/test/RunTests.sh +1 -1
- package/common/cpp/test/src/AudioParamTest.cpp +10 -10
- package/common/cpp/test/src/AudioScheduledSourceTest.cpp +31 -15
- package/common/cpp/test/src/ConstantSourceTest.cpp +16 -14
- package/common/cpp/test/src/DelayTest.cpp +14 -13
- package/common/cpp/test/src/GainTest.cpp +10 -9
- package/common/cpp/test/src/IIRFilterTest.cpp +4 -4
- package/common/cpp/test/src/OscillatorTest.cpp +2 -2
- package/common/cpp/test/src/StereoPannerTest.cpp +14 -12
- package/common/cpp/test/src/biquad/BiquadFilterTest.cpp +25 -25
- package/common/cpp/test/src/biquad/BiquadFilterTest.h +3 -5
- package/package.json +1 -1
|
@@ -12,15 +12,16 @@
|
|
|
12
12
|
|
|
13
13
|
namespace audioapi {
|
|
14
14
|
|
|
15
|
-
AudioBufferSourceNode::AudioBufferSourceNode(
|
|
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
|
-
|
|
22
|
-
|
|
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
|
-
|
|
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 (
|
|
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()) *
|
|
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_,
|
|
103
|
-
playbackRateBus_ =
|
|
104
|
-
|
|
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
|
-
|
|
193
|
-
|
|
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
|
-
|
|
261
|
-
|
|
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_ *
|
|
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_ *
|
|
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
|
|
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
|
|
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 (
|
|
31
|
-
context
|
|
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
|
-
|
|
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
|
|
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
|
|
10
|
-
: AudioScheduledSourceNode(context)
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
41
|
-
|
|
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
|
-
|
|
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 =
|
|
63
|
-
static_cast<double>(startOffset) * 1.0 /
|
|
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
|
|
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
|
|
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
|
-
|
|
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_,
|
|
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
|
|
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
|
|
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
|
|
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_,
|
|
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
|
-
|
|
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",
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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,
|
|
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(
|
|
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(
|
|
35
|
+
explicit WorkletSourceNode(
|
|
36
|
+
std::shared_ptr<BaseAudioContext> context,
|
|
37
|
+
WorkletsRunner &&workletRunner);
|
|
34
38
|
|
|
35
39
|
protected:
|
|
36
40
|
std::shared_ptr<AudioBus> processNode(
|