Skip to content

Commit 2b16355

Browse files
maciejmakowski2003Maciej Makowski
andauthored
Fix/initializing context/deconstruction bug (#295)
* refactor: added extra checks to AudioContext * fix: fixed preparing node for deconstruction process --------- Co-authored-by: Maciej Makowski <maciej.makowski2608@gmail.com>
1 parent c44e777 commit 2b16355

File tree

7 files changed

+71
-67
lines changed

7 files changed

+71
-67
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ AudioContext::AudioContext(float sampleRate) : BaseAudioContext() {
3535
}
3636

3737
AudioContext::~AudioContext() {
38-
if (isRunning()) {
38+
if (isClosed()) {
3939
return;
4040
}
4141

@@ -48,7 +48,7 @@ void AudioContext::close() {
4848
}
4949

5050
std::function<void(AudioBus *, int)> AudioContext::renderAudio() {
51-
if (!isRunning()) {
51+
if (!isRunning() || !destination_) {
5252
return [](AudioBus *, int) {};
5353
}
5454

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

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ AudioNode::AudioNode(BaseAudioContext *context) : context_(context) {
1313
}
1414

1515
AudioNode::~AudioNode() {
16-
isInitialized_ = false;
1716
cleanup();
1817
}
1918

@@ -42,14 +41,9 @@ void AudioNode::connect(const std::shared_ptr<AudioNode> &node) {
4241
shared_from_this(), node, AudioNodeManager::ConnectionType::CONNECT);
4342
}
4443

45-
void AudioNode::connectNode(const std::shared_ptr<AudioNode> &node) {
46-
outputNodes_.push_back(node);
47-
node->onInputConnected(this);
48-
}
49-
5044
void AudioNode::disconnect() {
5145
for (auto &outputNode : outputNodes_) {
52-
disconnectNode(outputNode);
46+
disconnect(outputNode);
5347
}
5448
}
5549

@@ -58,16 +52,6 @@ void AudioNode::disconnect(const std::shared_ptr<AudioNode> &node) {
5852
shared_from_this(), node, AudioNodeManager::ConnectionType::DISCONNECT);
5953
}
6054

61-
void AudioNode::disconnectNode(const std::shared_ptr<AudioNode> &node) {
62-
node->onInputDisconnected(this);
63-
64-
auto position = std::find(outputNodes_.begin(), outputNodes_.end(), node);
65-
66-
if (position != outputNodes_.end()) {
67-
outputNodes_.erase(position);
68-
}
69-
}
70-
7155
bool AudioNode::isEnabled() const {
7256
return isEnabled_;
7357
}
@@ -186,10 +170,30 @@ AudioBus *AudioNode::processAudio(AudioBus *outputBus, int framesToProcess) {
186170
}
187171

188172
void AudioNode::cleanup() {
173+
isInitialized_ = false;
174+
175+
for (const auto &outputNode : outputNodes_) {
176+
outputNode->onInputDisconnected(this);
177+
}
178+
179+
for (const auto &inputNode : inputNodes_) {
180+
inputNode->disconnectNode(shared_from_this());
181+
}
182+
189183
outputNodes_.clear();
190184
inputNodes_.clear();
191185
}
192186

187+
void AudioNode::connectNode(const std::shared_ptr<AudioNode> &node) {
188+
outputNodes_.insert(node);
189+
node->onInputConnected(this);
190+
}
191+
192+
void AudioNode::disconnectNode(const std::shared_ptr<AudioNode> &node) {
193+
outputNodes_.erase(node);
194+
node->onInputDisconnected(this);
195+
}
196+
193197
void AudioNode::onInputEnabled() {
194198
numberOfEnabledInputNodes_ += 1;
195199

@@ -211,7 +215,7 @@ void AudioNode::onInputConnected(AudioNode *node) {
211215
return;
212216
}
213217

214-
inputNodes_.push_back(node);
218+
inputNodes_.insert(node);
215219

216220
if (node->isEnabled()) {
217221
onInputEnabled();
@@ -223,23 +227,11 @@ void AudioNode::onInputDisconnected(AudioNode *node) {
223227
return;
224228
}
225229

226-
auto position = std::find(inputNodes_.begin(), inputNodes_.end(), node);
227-
228-
if (position != inputNodes_.end()) {
229-
inputNodes_.erase(position);
230-
}
231-
232-
if (!inputNodes_.empty()) {
233-
return;
234-
}
230+
inputNodes_.erase(node);
235231

236232
if (isEnabled()) {
237233
node->onInputDisabled();
238234
}
239-
240-
for (const auto &outputNode : outputNodes_) {
241-
disconnectNode(outputNode);
242-
}
243235
}
244236

245237
} // namespace audioapi

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#include <memory>
44
#include <string>
5-
#include <vector>
5+
#include <unordered_set>
66
#include <cstddef>
77

88
#include "ChannelCountMode.h"
@@ -18,6 +18,7 @@ class AudioNode : public std::enable_shared_from_this<AudioNode> {
1818
public:
1919
explicit AudioNode(BaseAudioContext *context);
2020
virtual ~AudioNode();
21+
2122
int getNumberOfInputs() const;
2223
int getNumberOfOutputs() const;
2324
int getChannelCount() const;
@@ -45,8 +46,8 @@ class AudioNode : public std::enable_shared_from_this<AudioNode> {
4546
ChannelInterpretation channelInterpretation_ =
4647
ChannelInterpretation::SPEAKERS;
4748

48-
std::vector<AudioNode *> inputNodes_ = {};
49-
std::vector<std::shared_ptr<AudioNode>> outputNodes_ = {};
49+
std::unordered_set<AudioNode *> inputNodes_ = {};
50+
std::unordered_set<std::shared_ptr<AudioNode>> outputNodes_ = {};
5051

5152
int numberOfEnabledInputNodes_ = 0;
5253
bool isInitialized_ = false;

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

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ namespace audioapi {
77

88
AudioNodeManager::~AudioNodeManager() {
99
audioNodesToConnect_.clear();
10-
sourceNodes_.clear();
1110
}
1211

1312
void AudioNodeManager::addPendingConnection(
@@ -19,31 +18,33 @@ void AudioNodeManager::addPendingConnection(
1918
audioNodesToConnect_.emplace_back(from, to, type);
2019
}
2120

22-
void AudioNodeManager::addSourceNode(const std::shared_ptr<AudioNode> &node) {
23-
Locker lock(getGraphLock());
24-
25-
sourceNodes_.push_back(node);
26-
}
27-
2821
void AudioNodeManager::preProcessGraph() {
2922
if (!Locker::tryLock(getGraphLock())) {
3023
return;
3124
}
3225

3326
settlePendingConnections();
34-
removeFinishedSourceNodes();
27+
prepareNodesForDestruction();
3528
}
3629

3730
std::mutex &AudioNodeManager::getGraphLock() {
3831
return graphLock_;
3932
}
4033

34+
void AudioNodeManager::addNode(const std::shared_ptr<AudioNode> &node) {
35+
Locker lock(getGraphLock());
36+
37+
nodes_.insert(node);
38+
}
39+
4140
void AudioNodeManager::settlePendingConnections() {
4241
for (auto &connection : audioNodesToConnect_) {
4342
std::shared_ptr<AudioNode> from = std::get<0>(connection);
4443
std::shared_ptr<AudioNode> to = std::get<1>(connection);
4544
ConnectionType type = std::get<2>(connection);
4645

46+
// add assert to check if from and to are neither null nor uninitialized
47+
4748
if (type == ConnectionType::CONNECT) {
4849
from->connectNode(to);
4950
} else {
@@ -54,16 +55,11 @@ void AudioNodeManager::settlePendingConnections() {
5455
audioNodesToConnect_.clear();
5556
}
5657

57-
void AudioNodeManager::removeFinishedSourceNodes() {
58-
for (auto it = sourceNodes_.begin(); it != sourceNodes_.end();) {
59-
auto currentNode = it->get();
60-
// Release the source node if use count is equal to 1 (this vector)
61-
if (!currentNode->isEnabled() && it->use_count() == 1) {
62-
for (auto &outputNode : currentNode->outputNodes_) {
63-
currentNode->disconnectNode(outputNode);
64-
}
65-
66-
it = sourceNodes_.erase(it);
58+
void AudioNodeManager::prepareNodesForDestruction() {
59+
for (auto it = nodes_.begin(); it != nodes_.end();) {
60+
if (it->use_count() == 1) {
61+
it->get()->cleanup();
62+
it = nodes_.erase(it);
6763
} else {
6864
++it;
6965
}

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <mutex>
55
#include <tuple>
66
#include <vector>
7+
#include <unordered_set>
78

89
namespace audioapi {
910

@@ -15,28 +16,32 @@ class AudioNodeManager {
1516
AudioNodeManager() = default;
1617
~AudioNodeManager();
1718

19+
std::mutex &getGraphLock();
20+
1821
void preProcessGraph();
22+
1923
void addPendingConnection(
2024
const std::shared_ptr<AudioNode> &from,
2125
const std::shared_ptr<AudioNode> &to,
2226
ConnectionType type);
2327

24-
void addSourceNode(const std::shared_ptr<AudioNode> &node);
25-
26-
std::mutex &getGraphLock();
28+
void addNode(const std::shared_ptr<AudioNode> &node);
2729

2830
private:
2931
std::mutex graphLock_;
3032

31-
std::vector<std::shared_ptr<AudioNode>> sourceNodes_;
33+
// all nodes created in the context
34+
std::unordered_set<std::shared_ptr<AudioNode>> nodes_;
35+
36+
// connections to be settled
3237
std::vector<std::tuple<
3338
std::shared_ptr<AudioNode>,
3439
std::shared_ptr<AudioNode>,
3540
ConnectionType>>
3641
audioNodesToConnect_;
3742

3843
void settlePendingConnections();
39-
void removeFinishedSourceNodes();
44+
void prepareNodesForDestruction();
4045
};
4146

4247
} // namespace audioapi

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ AudioScheduledSourceNode::AudioScheduledSourceNode(BaseAudioContext *context)
1818
void AudioScheduledSourceNode::start(double time) {
1919
playbackState_ = PlaybackState::SCHEDULED;
2020
startTime_ = time;
21-
22-
context_->getNodeManager()->addSourceNode(shared_from_this());
2321
}
2422

2523
void AudioScheduledSourceNode::stop(double time) {

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

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,23 +42,33 @@ std::shared_ptr<AudioDestinationNode> BaseAudioContext::getDestination() {
4242
}
4343

4444
std::shared_ptr<OscillatorNode> BaseAudioContext::createOscillator() {
45-
return std::make_shared<OscillatorNode>(this);
45+
auto oscillator = std::make_shared<OscillatorNode>(this);
46+
nodeManager_->addNode(oscillator);
47+
return oscillator;
4648
}
4749

4850
std::shared_ptr<GainNode> BaseAudioContext::createGain() {
49-
return std::make_shared<GainNode>(this);
51+
auto gain = std::make_shared<GainNode>(this);
52+
nodeManager_->addNode(gain);
53+
return gain;
5054
}
5155

5256
std::shared_ptr<StereoPannerNode> BaseAudioContext::createStereoPanner() {
53-
return std::make_shared<StereoPannerNode>(this);
57+
auto stereoPanner = std::make_shared<StereoPannerNode>(this);
58+
nodeManager_->addNode(stereoPanner);
59+
return stereoPanner;
5460
}
5561

5662
std::shared_ptr<BiquadFilterNode> BaseAudioContext::createBiquadFilter() {
57-
return std::make_shared<BiquadFilterNode>(this);
63+
auto biquadFilter = std::make_shared<BiquadFilterNode>(this);
64+
nodeManager_->addNode(biquadFilter);
65+
return biquadFilter;
5866
}
5967

6068
std::shared_ptr<AudioBufferSourceNode> BaseAudioContext::createBufferSource() {
61-
return std::make_shared<AudioBufferSourceNode>(this);
69+
auto bufferSource = std::make_shared<AudioBufferSourceNode>(this);
70+
nodeManager_->addNode(bufferSource);
71+
return bufferSource;
6272
}
6373

6474
std::shared_ptr<AudioBuffer> BaseAudioContext::createBuffer(
@@ -78,7 +88,9 @@ std::shared_ptr<PeriodicWave> BaseAudioContext::createPeriodicWave(
7888
}
7989

8090
std::shared_ptr<AnalyserNode> BaseAudioContext::createAnalyser() {
81-
return std::make_shared<AnalyserNode>(this);
91+
auto analyser = std::make_shared<AnalyserNode>(this);
92+
nodeManager_->addNode(analyser);
93+
return analyser;
8294
}
8395

8496
std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioDataSource(

0 commit comments

Comments
 (0)