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;