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);