Fixing audio runtimes. Race condition when completing in the audio completed callback thread! Want to add a test here but ran out of time! Diffs= 8ecc99130 Fixing audio runtimes. (#7007) Co-authored-by: Luigi Rosso <luigi-rosso@users.noreply.github.com>
diff --git a/.rive_head b/.rive_head index ed40a47..406e3a5 100644 --- a/.rive_head +++ b/.rive_head
@@ -1 +1 @@ -0bc446fad2a568a7088fdaa122af0de2de1dc940 +8ecc99130db737d49ce0889501c421bd53b58f9e
diff --git a/include/rive/animation/state_machine_instance.hpp b/include/rive/animation/state_machine_instance.hpp index 67369e6..98a5693 100644 --- a/include/rive/animation/state_machine_instance.hpp +++ b/include/rive/animation/state_machine_instance.hpp
@@ -51,7 +51,7 @@ template <typename SMType, typename InstType> InstType* getNamedInput(const std::string& name) const; - void notifyEventListeners(std::vector<EventReport> events, NestedArtboard* source); + void notifyEventListeners(const std::vector<EventReport>& events, NestedArtboard* source); void sortHitComponents(); public: @@ -120,6 +120,7 @@ /// Gets a reported event at an index < reportedEventCount(). const EventReport reportedEventAt(std::size_t index) const; + bool playsAudio() override { return true; } private: std::vector<EventReport> m_reportedEvents;
diff --git a/include/rive/audio/audio_engine.hpp b/include/rive/audio/audio_engine.hpp index e23f539..a49f669 100644 --- a/include/rive/audio/audio_engine.hpp +++ b/include/rive/audio/audio_engine.hpp
@@ -7,6 +7,7 @@ #include <vector> #include <stdio.h> #include <cstdint> +#include <mutex> typedef struct ma_engine ma_engine; typedef struct ma_sound ma_sound; @@ -60,6 +61,9 @@ AudioEngine(ma_engine* engine); ma_device* m_device; ma_engine* m_engine; + std::mutex m_mutex; + + void soundCompleted(rcp<AudioSound> sound); std::vector<rcp<AudioSound>> m_completedSounds; rcp<AudioSound> m_playingSoundsHead;
diff --git a/include/rive/audio_event.hpp b/include/rive/audio_event.hpp index cd67c6c..2844e9c 100644 --- a/include/rive/audio_event.hpp +++ b/include/rive/audio_event.hpp
@@ -13,6 +13,7 @@ void setAsset(FileAsset* asset) override; uint32_t assetId() override; void trigger(const CallbackData& value) override; + void play(); #ifdef TESTING AudioAsset* asset() const { return (AudioAsset*)m_fileAsset; }
diff --git a/include/rive/core/field_types/core_callback_type.hpp b/include/rive/core/field_types/core_callback_type.hpp index 1c8ba62..a6bb93f 100644 --- a/include/rive/core/field_types/core_callback_type.hpp +++ b/include/rive/core/field_types/core_callback_type.hpp
@@ -9,6 +9,7 @@ public: virtual ~CallbackContext() {} virtual void reportEvent(Event* event, float secondsDelay = 0.0f) {} + virtual bool playsAudio() { return false; } }; class CallbackData
diff --git a/include/rive/relative_local_asset_loader.hpp b/include/rive/relative_local_asset_loader.hpp index 6056c9c..c4dc317 100644 --- a/include/rive/relative_local_asset_loader.hpp +++ b/include/rive/relative_local_asset_loader.hpp
@@ -36,6 +36,11 @@ { std::string filename = m_Path + asset.uniqueFilename(); FILE* fp = fopen(filename.c_str(), "rb"); + if (fp == nullptr) + { + fprintf(stderr, "Failed to find file at %s\n", filename.c_str()); + return false; + } fseek(fp, 0, SEEK_END); const size_t length = ftell(fp);
diff --git a/src/animation/state_machine_instance.cpp b/src/animation/state_machine_instance.cpp index 0348c6e..b75642a 100644 --- a/src/animation/state_machine_instance.cpp +++ b/src/animation/state_machine_instance.cpp
@@ -24,6 +24,7 @@ #include "rive/nested_artboard.hpp" #include "rive/shapes/shape.hpp" #include "rive/math/math_types.hpp" +#include "rive/audio_event.hpp" #include <unordered_map> using namespace rive; @@ -782,7 +783,7 @@ return m_reportedEvents[index]; } -void StateMachineInstance::notifyEventListeners(std::vector<EventReport> events, +void StateMachineInstance::notifyEventListeners(const std::vector<EventReport>& events, NestedArtboard* source) { if (events.size() > 0) @@ -826,5 +827,14 @@ { m_parentStateMachineInstance->notifyEventListeners(events, m_parentNestedArtboard); } + + for (auto report : events) + { + auto event = report.event(); + if (event->is<AudioEvent>()) + { + event->as<AudioEvent>()->play(); + } + } } }
diff --git a/src/audio/audio_engine.cpp b/src/audio/audio_engine.cpp index 268e22e..c63bb69 100644 --- a/src/audio/audio_engine.cpp +++ b/src/audio/audio_engine.cpp
@@ -25,9 +25,17 @@ void AudioEngine::SoundCompleted(void* pUserData, ma_sound* pSound) { AudioSound* audioSound = (AudioSound*)pUserData; + auto engine = audioSound->m_engine; + engine->soundCompleted(ref_rcp(audioSound)); +} - auto next = audioSound->m_nextPlaying; - auto prev = audioSound->m_prevPlaying; +void AudioEngine::soundCompleted(rcp<AudioSound> sound) +{ + std::unique_lock<std::mutex> lock(m_mutex); + m_completedSounds.push_back(sound); + + auto next = sound->m_nextPlaying; + auto prev = sound->m_prevPlaying; if (next != nullptr) { next->m_prevPlaying = prev; @@ -37,16 +45,13 @@ prev->m_nextPlaying = next; } - auto engine = audioSound->m_engine; - if (engine->m_playingSoundsHead.get() == audioSound) + if (m_playingSoundsHead == sound) { - engine->m_playingSoundsHead = next; + m_playingSoundsHead = next; } - // Unlink audio sound. - engine->m_completedSounds.push_back(ref_rcp(audioSound)); - audioSound->m_nextPlaying = nullptr; - audioSound->m_prevPlaying = nullptr; + sound->m_nextPlaying = nullptr; + sound->m_prevPlaying = nullptr; } #ifdef WITH_RIVE_AUDIO_TOOLS @@ -182,6 +187,7 @@ uint64_t endTime, uint64_t soundStartTime) { + std::unique_lock<std::mutex> lock(m_mutex); // We have to dispose completed sounds out of the completed callback. So we // do it on next play or at destruct. for (auto sound : m_completedSounds)
diff --git a/src/audio_event.cpp b/src/audio_event.cpp index 1ba130b..d0d8098 100644 --- a/src/audio_event.cpp +++ b/src/audio_event.cpp
@@ -6,10 +6,8 @@ using namespace rive; -void AudioEvent::trigger(const CallbackData& value) +void AudioEvent::play() { - Super::trigger(value); - #ifdef WITH_RIVE_AUDIO auto audioAsset = (AudioAsset*)m_fileAsset; if (audioAsset == nullptr) @@ -36,6 +34,16 @@ #endif } +void AudioEvent::trigger(const CallbackData& value) +{ + Super::trigger(value); + if (!value.context()->playsAudio()) + { + // Context won't play audio, we'll do it ourselves. + play(); + } +} + StatusCode AudioEvent::import(ImportStack& importStack) { auto result = registerReferencer(importStack);