diff --git a/.rive_head b/.rive_head index f2c8502f..58e5b308 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 8bdf33c4..e709ec7e 100644 --- a/include/rive/audio/audio_engine.hpp +++ b/include/rive/audio/audio_engine.hpp @@ -13,6 +13,7 @@ typedef struct ma_engine ma_engine; 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 @@ class AudioEngine : public RefCnt 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 sound); diff --git a/src/audio/audio_engine.cpp b/src/audio/audio_engine.cpp index 8f957e84..da487029 100644 --- a/src/audio/audio_engine.cpp +++ b/src/audio/audio_engine.cpp @@ -163,10 +163,40 @@ void AudioEngine::stop() { ma_engine_stop(m_engine); } rcp 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 @@ rcp AudioEngine::Make(uint32_t numChannels, uint32_t sampleRate) 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(new AudioEngine(engine)); + return rcp(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 AudioEngine::play(rcp source, @@ -367,6 +405,16 @@ AudioEngine::~AudioEngine() } 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;