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;