Set audio to mix on for iOS (simulator) and Catalyst
Sets audio on iOS (simulator) and Catalyst to mix rather than duck (default). This builds on #7366 by attempting to clean the code up a little, as well as make the changes only have effect when building for Apple platforms.
- [x] Update AudioEngine to contain a pointer to the engine context
- This is not exposed via public getter since it's not used outside of the AudioEngine, but was required for memory management
- [x] Configure the audio context to mix for Core Audio (only when building for Apple platforms)
Tested on:
- [x] iOS
- [x] iPadOS
- [x] macOS Catalyst
- [x] macOS
Diffs=
238bf2fe1 Set audio to mix on for iOS (simulator) and Catalyst (#7555)
Co-authored-by: David Skuza <david@rive.app>
diff --git a/.rive_head b/.rive_head
index f2c8502..58e5b30 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-ca56d756514d50c68ea3306739e6ad177caee2ab
+238bf2fe1872740896a75629e8e349f53938b589
diff --git a/include/rive/audio/audio_engine.hpp b/include/rive/audio/audio_engine.hpp
index 8bdf33c..e709ec7 100644
--- a/include/rive/audio/audio_engine.hpp
+++ b/include/rive/audio/audio_engine.hpp
@@ -13,6 +13,7 @@
typedef struct ma_sound ma_sound;
typedef struct ma_device ma_device;
typedef struct ma_node_base ma_node_base;
+typedef struct ma_context ma_context;
namespace rive
{
@@ -67,9 +68,10 @@
size_t playingSoundCount();
#endif
private:
- AudioEngine(ma_engine* engine);
+ AudioEngine(ma_engine* engine, ma_context* context);
ma_device* m_device;
ma_engine* m_engine;
+ ma_context* m_context;
std::mutex m_mutex;
void soundCompleted(rcp<AudioSound> sound);
diff --git a/src/audio/audio_engine.cpp b/src/audio/audio_engine.cpp
index 8f957e8..da48702 100644
--- a/src/audio/audio_engine.cpp
+++ b/src/audio/audio_engine.cpp
@@ -163,10 +163,40 @@
rcp<AudioEngine> AudioEngine::Make(uint32_t numChannels, uint32_t sampleRate)
{
+// I _think_ MA_NO_DEVICE_IO is defined when building for Unity; otherwise, it seems to pass
+// "standard" building When defined, pContext is unavailable, which causes build errors when
+// building Unity for iOS. - David
+#if defined(MA_HAS_COREAUDIO) && !defined(MA_NO_DEVICE_IO)
+ // Used for configuration only, and isn't referenced past the usage of ma_context_init; thus,
+ // can be locally scoped. Uses the "logical" defaults from miniaudio, and updates only what we
+ // need. This should automatically set available backends in priority order based on the target
+ // it's built for, which in the case of Apple is Core Audio first.
+ ma_context_config contextConfig = ma_context_config_init();
+ contextConfig.coreaudio.sessionCategoryOptions = ma_ios_session_category_option_mix_with_others;
+
+ // We only need to initialize space for the context if we're targeting Apple platforms
+ ma_context* context = (ma_context*)malloc(sizeof(ma_context));
+
+ if (ma_context_init(NULL, 0, &contextConfig, context) != MA_SUCCESS)
+ {
+ free(context);
+ context = nullptr;
+ }
+#else
+ ma_context* context = nullptr;
+#endif
+
ma_engine_config engineConfig = ma_engine_config_init();
engineConfig.channels = numChannels;
engineConfig.sampleRate = sampleRate;
+#if defined(MA_HAS_COREAUDIO) && !defined(MA_NO_DEVICE_IO)
+ if (context != nullptr)
+ {
+ engineConfig.pContext = context;
+ }
+#endif
+
#ifdef EXTERNAL_RIVE_AUDIO_ENGINE
engineConfig.noDevice = MA_TRUE;
#endif
@@ -175,19 +205,27 @@
if (ma_engine_init(&engineConfig, engine) != MA_SUCCESS)
{
+#if defined(MA_HAS_COREAUDIO) && !defined(MA_NO_DEVICE_IO)
+ if (context != nullptr)
+ {
+ ma_context_uninit(context);
+ free(context);
+ context = nullptr;
+ }
+#endif
fprintf(stderr, "AudioEngine::Make - failed to init engine\n");
delete engine;
return nullptr;
}
- return rcp<AudioEngine>(new AudioEngine(engine));
+ return rcp<AudioEngine>(new AudioEngine(engine, context));
}
uint32_t AudioEngine::channels() const { return ma_engine_get_channels(m_engine); }
uint32_t AudioEngine::sampleRate() const { return ma_engine_get_sample_rate(m_engine); }
-AudioEngine::AudioEngine(ma_engine* engine) :
- m_device(ma_engine_get_device(engine)), m_engine(engine)
+AudioEngine::AudioEngine(ma_engine* engine, ma_context* context) :
+ m_device(ma_engine_get_device(engine)), m_engine(engine), m_context(context)
{}
rcp<AudioSound> AudioEngine::play(rcp<AudioSource> source,
@@ -367,6 +405,16 @@
}
m_completedSounds.clear();
+#if defined(MA_HAS_COREAUDIO) && !defined(MA_NO_DEVICE_IO)
+ // m_context is only set when Core Audio is available
+ if (m_context != nullptr)
+ {
+ ma_context_uninit(m_context);
+ free(m_context);
+ m_context = nullptr;
+ }
+#endif
+
ma_engine_uninit(m_engine);
delete m_engine;