From 261b8ac423f162e72db891b3741d3798341a2115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20S=C4=99k?= Date: Fri, 29 Nov 2024 13:27:23 +0100 Subject: [PATCH] fix: base audio context construction + audio player start stop events (#215) --- .../src/examples/DrumMachine/usePlayer.tsx | 4 ++++ .../src/main/cpp/AudioPlayer/AudioPlayer.cpp | 8 +++++++- .../src/main/cpp/AudioPlayer/AudioPlayer.h | 1 + .../common/cpp/core/AudioContext.cpp | 13 +++++------- .../common/cpp/core/AudioDestinationNode.cpp | 8 ++++---- .../common/cpp/core/BaseAudioContext.cpp | 20 +++++++++++++++++-- .../common/cpp/core/BaseAudioContext.h | 3 +++ 7 files changed, 42 insertions(+), 15 deletions(-) diff --git a/apps/common-app/src/examples/DrumMachine/usePlayer.tsx b/apps/common-app/src/examples/DrumMachine/usePlayer.tsx index 0c782a33..29447313 100644 --- a/apps/common-app/src/examples/DrumMachine/usePlayer.tsx +++ b/apps/common-app/src/examples/DrumMachine/usePlayer.tsx @@ -133,6 +133,10 @@ export default function usePlayer(options: PlayerOptions) { playingInstruments.value = getPlayingInstruments(); } + return () => { + audioContext.close(); + }; + // \/ Shared values are not necessary in deps array // eslint-disable-next-line react-hooks/exhaustive-deps }, [isPlaying, setup]); diff --git a/packages/react-native-audio-api/android/src/main/cpp/AudioPlayer/AudioPlayer.cpp b/packages/react-native-audio-api/android/src/main/cpp/AudioPlayer/AudioPlayer.cpp index f0954670..3e5510a1 100644 --- a/packages/react-native-audio-api/android/src/main/cpp/AudioPlayer/AudioPlayer.cpp +++ b/packages/react-native-audio-api/android/src/main/cpp/AudioPlayer/AudioPlayer.cpp @@ -21,6 +21,7 @@ AudioPlayer::AudioPlayer(const std::function &renderAudio) ->openStream(mStream_); mBus_ = std::make_shared(getSampleRate(), getBufferSizeInFrames(), CHANNEL_COUNT); + isInitialized_ = true; } int AudioPlayer::getSampleRate() const { @@ -38,6 +39,8 @@ void AudioPlayer::start() { } void AudioPlayer::stop() { + isInitialized_ = false; + if (mStream_) { mStream_->requestStop(); mStream_->close(); @@ -49,8 +52,11 @@ DataCallbackResult AudioPlayer::onAudioReady( AudioStream *oboeStream, void *audioData, int32_t numFrames) { - auto buffer = static_cast(audioData); + if (!isInitialized_) { + return DataCallbackResult::Continue; + } + auto buffer = static_cast(audioData); renderAudio_(mBus_.get(), numFrames); // TODO: optimize this with SIMD? diff --git a/packages/react-native-audio-api/android/src/main/cpp/AudioPlayer/AudioPlayer.h b/packages/react-native-audio-api/android/src/main/cpp/AudioPlayer/AudioPlayer.h index 26383f07..fc1f5684 100644 --- a/packages/react-native-audio-api/android/src/main/cpp/AudioPlayer/AudioPlayer.h +++ b/packages/react-native-audio-api/android/src/main/cpp/AudioPlayer/AudioPlayer.h @@ -28,6 +28,7 @@ class AudioPlayer : public AudioStreamDataCallback { std::function renderAudio_; std::shared_ptr mStream_; std::shared_ptr mBus_; + bool isInitialized_ = false; }; } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/core/AudioContext.cpp b/packages/react-native-audio-api/common/cpp/core/AudioContext.cpp index 1fb3608f..3e43de30 100644 --- a/packages/react-native-audio-api/common/cpp/core/AudioContext.cpp +++ b/packages/react-native-audio-api/common/cpp/core/AudioContext.cpp @@ -9,16 +9,13 @@ namespace audioapi { -AudioContext::AudioContext() : BaseAudioContext() {} +AudioContext::AudioContext() : BaseAudioContext() { + audioPlayer_->start(); +} void AudioContext::close() { state_ = ContextState::CLOSED; - - if (audioPlayer_) { - audioPlayer_->stop(); - } - - audioPlayer_.reset(); - destination_.reset(); + audioPlayer_->stop(); } + } // namespace audioapi diff --git a/packages/react-native-audio-api/common/cpp/core/AudioDestinationNode.cpp b/packages/react-native-audio-api/common/cpp/core/AudioDestinationNode.cpp index 898d2258..560538d3 100644 --- a/packages/react-native-audio-api/common/cpp/core/AudioDestinationNode.cpp +++ b/packages/react-native-audio-api/common/cpp/core/AudioDestinationNode.cpp @@ -24,13 +24,13 @@ double AudioDestinationNode::getCurrentTime() const { } void AudioDestinationNode::renderAudio(AudioBus *destinationBus, int32_t numFrames) { - context_->getNodeManager()->preProcessGraph(); - destinationBus->zero(); - - if (!numFrames) { + if (!numFrames || !destinationBus || !isInitialized_) { return; } + context_->getNodeManager()->preProcessGraph(); + destinationBus->zero(); + AudioBus* processedBus = processAudio(destinationBus, numFrames); if (processedBus && processedBus != destinationBus) { diff --git a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp index 9df72dc9..8acf9c05 100644 --- a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp +++ b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.cpp @@ -30,11 +30,19 @@ BaseAudioContext::BaseAudioContext() { sampleRate_ = audioPlayer_->getSampleRate(); bufferSizeInFrames_ = audioPlayer_->getBufferSizeInFrames(); - audioPlayer_->start(); nodeManager_ = std::make_shared(); destination_ = std::make_shared(this); } +BaseAudioContext::~BaseAudioContext() { + if (isRunning()) { + return; + } + + state_ = ContextState::CLOSED; + audioPlayer_->stop(); +} + std::string BaseAudioContext::getState() { return BaseAudioContext::toString(state_); } @@ -96,7 +104,7 @@ std::shared_ptr BaseAudioContext::createPeriodicWave( } std::function BaseAudioContext::renderAudio() { - if (state_ == ContextState::CLOSED) { + if (isClosed()) { return [](AudioBus *, int) {}; } @@ -109,6 +117,14 @@ AudioNodeManager* BaseAudioContext::getNodeManager() { return nodeManager_.get(); } +bool BaseAudioContext::isRunning() const { + return state_ == ContextState::RUNNING; +} + +bool BaseAudioContext::isClosed() const { + return state_ == ContextState::CLOSED; +} + std::string BaseAudioContext::toString(ContextState state) { switch (state) { case ContextState::SUSPENDED: diff --git a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h index fb9052cf..e5d4ffbd 100644 --- a/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h +++ b/packages/react-native-audio-api/common/cpp/core/BaseAudioContext.h @@ -31,6 +31,7 @@ class IOSAudioPlayer; class BaseAudioContext { public: BaseAudioContext(); + ~BaseAudioContext(); std::string getState(); [[nodiscard]] int getSampleRate() const; [[nodiscard]] double getCurrentTime() const; @@ -54,6 +55,8 @@ class BaseAudioContext { std::function renderAudio(); AudioNodeManager* getNodeManager(); + bool isRunning() const; + bool isClosed() const; protected: static std::string toString(ContextState state);