Skip to content

Commit 6d61fbd

Browse files
committed
feat: proper deconstruction
1 parent c997218 commit 6d61fbd

12 files changed

+48
-82
lines changed

apps/common-app/src/examples/DrumMachine/usePlayer.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,9 @@ export default function usePlayer(options: PlayerOptions) {
133133
playingInstruments.value = getPlayingInstruments();
134134
}
135135

136-
// return () => {
137-
// console.log('Closing audio context');
138-
// audioContext.close();
139-
// };
136+
return () => {
137+
audioContext.close();
138+
};
140139
// \/ Shared values are not necessary in deps array
141140
// eslint-disable-next-line react-hooks/exhaustive-deps
142141
}, [isPlaying, setup]);

packages/react-native-audio-api/common/cpp/core/AudioBufferSourceNode.cpp

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ AudioBufferSourceNode::AudioBufferSourceNode(BaseAudioContext *context)
99
: AudioScheduledSourceNode(context), loop_(false), bufferIndex_(0) {
1010
numberOfInputs_ = 0;
1111
buffer_ = std::shared_ptr<AudioBuffer>(nullptr);
12+
isInitialized_ = true;
1213
}
1314

1415
bool AudioBufferSourceNode::getLoop() const {
@@ -51,6 +52,7 @@ void AudioBufferSourceNode::processNode(AudioBus* processingBus, int framesToPro
5152

5253
if (!loop_) {
5354
playbackState_ = PlaybackState::FINISHED;
55+
disable();
5456
}
5557

5658
return;
@@ -59,20 +61,31 @@ void AudioBufferSourceNode::processNode(AudioBus* processingBus, int framesToPro
5961
// The buffer is longer than the number of frames to process.
6062
// We have to keep track of where we are in the buffer.
6163
if (framesToProcess < buffer_->getLength()) {
62-
int processingBufferPosition = 0;
64+
int outputBusIndex = 0;
6365
int framesToCopy = 0;
6466

65-
while (processingBufferPosition < framesToProcess)
66-
{
67-
framesToCopy = std::min(framesToProcess, buffer_->getLength() - bufferIndex_);
67+
while (framesToProcess - outputBusIndex > 0) {
68+
framesToCopy = std::min(framesToProcess - outputBusIndex, buffer_->getLength() - bufferIndex_);
6869

69-
processingBus->copy(buffer_->bus_.get(), processingBufferPosition, bufferIndex_, framesToCopy);
70-
processingBufferPosition += framesToCopy;
71-
bufferIndex_ = (bufferIndex_ + framesToCopy) % buffer_->getLength();
70+
processingBus->copy(buffer_->bus_.get(), bufferIndex_, outputBusIndex, framesToCopy);
7271

73-
if (!loop_ && processingBufferPosition >= framesToCopy) {
74-
playbackState_ = PlaybackState::FINISHED;
75-
bufferIndex_ = 0;
72+
bufferIndex_ += framesToCopy;
73+
outputBusIndex += framesToCopy;
74+
75+
if (bufferIndex_ < buffer_->getLength()) {
76+
continue;
77+
}
78+
79+
80+
bufferIndex_ %= buffer_->getLength();
81+
82+
if (!loop_) {
83+
playbackState_ = PlaybackState::FINISHED;
84+
disable();
85+
86+
if (framesToProcess - outputBusIndex > 0) {
87+
processingBus->zero(outputBusIndex, framesToProcess - outputBusIndex);
88+
}
7689
}
7790
}
7891

@@ -84,7 +97,9 @@ void AudioBufferSourceNode::processNode(AudioBus* processingBus, int framesToPro
8497
// If we don't loop the buffer, copy it once and zero the remaining processing bus frames.
8598
processingBus->copy(buffer_->bus_.get());
8699
processingBus->zero(buffer_->getLength(), framesToProcess - buffer_->getLength());
100+
87101
playbackState_ = PlaybackState::FINISHED;
102+
disable();
88103

89104
return;
90105
}

packages/react-native-audio-api/common/cpp/core/AudioDestinationNode.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ AudioDestinationNode::AudioDestinationNode(BaseAudioContext *context)
1212
numberOfOutputs_ = 0;
1313
numberOfInputs_ = INT_MAX;
1414
channelCountMode_ = ChannelCountMode::EXPLICIT;
15+
isInitialized_ = true;
1516
}
1617

1718
std::size_t AudioDestinationNode::getCurrentSampleFrame() const {
@@ -24,7 +25,6 @@ double AudioDestinationNode::getCurrentTime() const {
2425

2526
void AudioDestinationNode::renderAudio(AudioBus *destinationBus, int32_t numFrames) {
2627
context_->getNodeManager()->preProcessGraph();
27-
2828
destinationBus->zero();
2929

3030
if (!numFrames) {
@@ -39,8 +39,6 @@ void AudioDestinationNode::renderAudio(AudioBus *destinationBus, int32_t numFram
3939

4040
destinationBus->normalize();
4141

42-
context_->getNodeManager()->postProcessGraph();
43-
4442
currentSampleFrame_ += numFrames;
4543
}
4644

packages/react-native-audio-api/common/cpp/core/AudioNode.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ AudioNode::AudioNode(BaseAudioContext *context) : context_(context) {
1212
}
1313

1414
AudioNode::~AudioNode() {
15+
isInitialized_ = false;
1516
cleanup();
1617
}
1718

@@ -39,17 +40,16 @@ void AudioNode::connect(const std::shared_ptr<AudioNode> &node) {
3940
context_->getNodeManager()->addPendingConnection(shared_from_this(), node, AudioNodeManager::ConnectionType::CONNECT);
4041
}
4142

42-
void AudioNode::connectNode(std::shared_ptr<AudioNode> &node) {
43+
void AudioNode::connectNode(const std::shared_ptr<AudioNode> &node) {
4344
outputNodes_.push_back(node);
44-
4545
node->onInputConnected(this);
4646
}
4747

4848
void AudioNode::disconnect(const std::shared_ptr<AudioNode> &node) {
4949
context_->getNodeManager()->addPendingConnection(shared_from_this(), node, AudioNodeManager::ConnectionType::DISCONNECT);
5050
}
5151

52-
void AudioNode::disconnectNode(std::shared_ptr<AudioNode> &node) {
52+
void AudioNode::disconnectNode(const std::shared_ptr<AudioNode> &node) {
5353
node->onInputDisconnected(this);
5454

5555
auto position = std::find(outputNodes_.begin(), outputNodes_.end(), node);
@@ -104,6 +104,10 @@ std::string AudioNode::toString(ChannelInterpretation interpretation) {
104104
}
105105

106106
AudioBus* AudioNode::processAudio(AudioBus* outputBus, int framesToProcess) {
107+
if (!isInitialized_) {
108+
return outputBus;
109+
}
110+
107111
std::size_t currentSampleFrame = context_->getCurrentSampleFrame();
108112

109113
// check if the node has already been processed for this rendering quantum
@@ -197,13 +201,12 @@ void AudioNode::onInputConnected(AudioNode *node) {
197201
void AudioNode::onInputDisconnected(AudioNode *node) {
198202
auto position = std::find(inputNodes_.begin(), inputNodes_.end(), node);
199203

200-
if (position == inputNodes_.end()) {
201-
return;
204+
if (position != inputNodes_.end()) {
205+
inputNodes_.erase(position);
202206
}
203207

204-
inputNodes_.erase(position);
205208

206-
if (inputNodes_.size() > 0 || outputNodes_.size() == 0) {
209+
if (inputNodes_.size() > 0) {
207210
return;
208211
}
209212

packages/react-native-audio-api/common/cpp/core/AudioNode.h

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class AudioNode : public std::enable_shared_from_this<AudioNode> {
4242
int numberOfOutputs_ = 1;
4343
int numberOfEnabledInputNodes_ = 0;
4444

45+
bool isInitialized_ = false;
4546
bool isEnabled_ = true;
4647

4748
std::size_t lastRenderedFrame_ { SIZE_MAX };
@@ -61,8 +62,8 @@ class AudioNode : public std::enable_shared_from_this<AudioNode> {
6162
AudioBus* processAudio(AudioBus* outputBus, int framesToProcess);
6263
virtual void processNode(AudioBus* processingBus, int framesToProcess) = 0;
6364

64-
void connectNode(std::shared_ptr<AudioNode> &node);
65-
void disconnectNode(std::shared_ptr<AudioNode> &node);
65+
void connectNode(const std::shared_ptr<AudioNode> &node);
66+
void disconnectNode(const std::shared_ptr<AudioNode> &node);
6667

6768
void onInputEnabled();
6869
void onInputDisabled();
@@ -71,32 +72,3 @@ class AudioNode : public std::enable_shared_from_this<AudioNode> {
7172
};
7273

7374
} // namespace audioapi
74-
75-
/*
76-
Audio node management and deletion
77-
78-
1. AudioSourceNode finishes playing, then:
79-
- it disables itself (so it won't by processed anymore)
80-
- if there is no reference from JS side, we can mark self for deletion
81-
- node that is marked for deletion should be disconnected from the graph first
82-
- it should "notify" connected nodes that it has been disabled (and potentially prepares for deletion)
83-
84-
2. Node gets "notified" that one of its sources is disabled:
85-
- it lowers the count of enabled sources
86-
- if the count of enabled sources is 0, disable itself
87-
- if there is no reference from JS side, we can mark self for deletion
88-
- node that is marked for deletion should be disconnected from the graph first
89-
- it should "notify" connected nodes that it has been disabled (and potentially prepares for deletion)
90-
91-
Translating into more technical terms:
92-
We use shared pointers for keeping output nodes
93-
We use shared pointers in audio node manager to keep track of all source nodes
94-
when audio source node finished playing it:
95-
- disables itself and tells all output nodes that it has been disabled
96-
- each node up to destination, checks their input nodes and if was its only active input node, it disables itself.
97-
- source node tells audio node manager to dereference it (only if it is the last reference to the source node).
98-
- audio manager in pre-process or post-process will remove the reference.
99-
- audio manager in pre-process or post-process will also have to check for source nodes with only one reference and delete them if already stopped.
100-
- deletion of the node will dereference all connected nodes, resulting in destroy'ing them if they are not referenced from JS side.
101-
102-
*/

packages/react-native-audio-api/common/cpp/core/AudioNodeManager.cpp

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ AudioNodeManager::AudioNodeManager() {}
99

1010
AudioNodeManager::~AudioNodeManager() {
1111
audioNodesToConnect_.clear();
12-
audioNodesToDelete_.clear();
12+
sourceNodes_.clear();
1313
}
1414

1515
void AudioNodeManager::addPendingConnection(const std::shared_ptr<AudioNode> &from, const std::shared_ptr<AudioNode> &to, ConnectionType type) {
@@ -18,12 +18,6 @@ void AudioNodeManager::addPendingConnection(const std::shared_ptr<AudioNode> &fr
1818
audioNodesToConnect_.push_back(std::make_tuple(from, to, type));
1919
}
2020

21-
void AudioNodeManager::setNodeToDelete(const std::shared_ptr<AudioNode> &node) {
22-
Locker lock(getGraphLock());
23-
24-
audioNodesToDelete_.push_back(node);
25-
}
26-
2721
void AudioNodeManager::addSourceNode(const std::shared_ptr<AudioNode> &node) {
2822
Locker lock(getGraphLock());
2923

@@ -35,17 +29,6 @@ void AudioNodeManager::preProcessGraph() {
3529
return;
3630
}
3731

38-
settlePendingDeletions();
39-
settlePendingConnections();
40-
removeFinishedSourceNodes();
41-
}
42-
43-
void AudioNodeManager::postProcessGraph() {
44-
if (!Locker::tryLock(getGraphLock())) {
45-
return;
46-
}
47-
48-
settlePendingDeletions();
4932
settlePendingConnections();
5033
removeFinishedSourceNodes();
5134
}
@@ -70,16 +53,11 @@ void AudioNodeManager::settlePendingConnections() {
7053
audioNodesToConnect_.clear();
7154
}
7255

73-
void AudioNodeManager::settlePendingDeletions() {
74-
audioNodesToDelete_.clear();
75-
}
76-
7756
void AudioNodeManager::removeFinishedSourceNodes() {
7857
for (auto it = sourceNodes_.begin(); it != sourceNodes_.end();) {
7958
auto currentNode = it->get();
8059
// Release the source node if use count is equal to 1 (this vector)
8160
if (!currentNode->isEnabled() && it->use_count() == 1) {
82-
8361
for (auto& outputNode : currentNode->outputNodes_) {
8462
currentNode->disconnectNode(outputNode);
8563
}

packages/react-native-audio-api/common/cpp/core/AudioNodeManager.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,8 @@ class AudioNodeManager {
1616
~AudioNodeManager();
1717

1818
void preProcessGraph();
19-
void postProcessGraph();
2019
void addPendingConnection(const std::shared_ptr<AudioNode> &from, const std::shared_ptr<AudioNode> &to, ConnectionType type);
2120

22-
void setNodeToDelete(const std::shared_ptr<AudioNode> &node);
2321
void addSourceNode(const std::shared_ptr<AudioNode> &node);
2422

2523
std::mutex& getGraphLock();
@@ -28,10 +26,8 @@ class AudioNodeManager {
2826
std::mutex graphLock_;
2927

3028
std::vector<std::shared_ptr<AudioNode>> sourceNodes_;
31-
std::vector<std::shared_ptr<AudioNode>> audioNodesToDelete_;
3229
std::vector<std::tuple<std::shared_ptr<AudioNode>, std::shared_ptr<AudioNode>, ConnectionType>> audioNodesToConnect_;
3330

34-
void settlePendingDeletions();
3531
void settlePendingConnections();
3632
void removeFinishedSourceNodes();
3733
};

packages/react-native-audio-api/common/cpp/core/AudioScheduledSourceNode.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace audioapi {
77
AudioScheduledSourceNode::AudioScheduledSourceNode(BaseAudioContext *context)
88
: AudioNode(context), playbackState_(PlaybackState::UNSCHEDULED) {
99
numberOfInputs_ = 0;
10+
isInitialized_ = true;
1011
}
1112

1213
void AudioScheduledSourceNode::start(double time) {

packages/react-native-audio-api/common/cpp/core/BiquadFilterNode.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ BiquadFilterNode::BiquadFilterNode(BaseAudioContext *context)
1919
gainParam_ = std::make_shared<AudioParam>(
2020
context, 0.0, MIN_FILTER_GAIN, MAX_FILTER_GAIN);
2121
type_ = BiquadFilterType::LOWPASS;
22+
isInitialized_ = true;
2223
}
2324

2425
std::string BiquadFilterNode::getType() {

packages/react-native-audio-api/common/cpp/core/GainNode.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace audioapi {
77

88
GainNode::GainNode(BaseAudioContext *context) : AudioNode(context) {
99
gainParam_ = std::make_shared<AudioParam>(context, 1.0, -MAX_GAIN, MAX_GAIN);
10+
isInitialized_ = true;
1011
}
1112

1213
std::shared_ptr<AudioParam> GainNode::getGainParam() const {

packages/react-native-audio-api/common/cpp/core/OscillatorNode.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ OscillatorNode::OscillatorNode(BaseAudioContext *context)
1313
std::make_shared<AudioParam>(context, 0.0, -MAX_DETUNE, MAX_DETUNE);
1414
type_ = OscillatorType::SINE;
1515
periodicWave_ = context_->getBasicWaveForm(type_);
16+
isInitialized_ = true;
1617
}
1718

1819
std::shared_ptr<AudioParam> OscillatorNode::getFrequencyParam() const {

packages/react-native-audio-api/common/cpp/core/StereoPannerNode.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ StereoPannerNode::StereoPannerNode(BaseAudioContext *context)
1212
: AudioNode(context) {
1313
channelCountMode_ = ChannelCountMode::CLAMPED_MAX;
1414
panParam_ = std::make_shared<AudioParam>(context, 0.0, -MAX_PAN, MAX_PAN);
15+
isInitialized_ = true;
1516
}
1617

1718
std::shared_ptr<AudioParam> StereoPannerNode::getPanParam() const {

0 commit comments

Comments
 (0)