Avoid initializing AudioEngine instance when audio is absent in AudioEvent #431
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Issue:
There is a frequent (but inconsistent) crash on Android devices with Android 10 (aka API 29) and below, caused when miniaudio disposes of its AudioEngine and attempts to free its audio buffers. This specific crash is really a race condition issue with miniaudio on Android 10-, but Rive indirectly triggers this through
StateMachineController.dispose()
. This results in a full crash, i.e. app quits completely and unexpectedly.More context on how this crash is triggered from Rive code...
When an
AudioEvent
is received inStateMachineController.applyEvents()
, an instance of Rive'sAudioEngine
is created through theaudioPlayer
getter, which consequently also initializes a miniaudio player. Note that this getter is currently invoked and theAudioEngine
is instantiated even if theAudioEvent
lacks an audio asset.While this is harmless on its own, in such cases where the
AudioEngine
is created, callingStateMachineController.dispose()
later also attempts to dispose the miniaudio player, resulting in the Android crash referenced above.The crash stack trace looks something like this...
On a related note, this condition also affects SoLoud, another Flutter package using miniaudio. SoLoud addresses it by switching to OpenSL for Android 10 and below.
Solution:
The perfect solution would be to fix the deref race conditions in miniaudio for Android 10.
But as a preventative measure in Rive, we can also avoid the crash circumstances for Rive users who don't use audio, by bypassing the miniaudio engine creation/disposal (through
StateMachineController.audioPlayer
) when audio is absent from anAudioEvent
.This change also provides a minor performance benefit by avoiding allocations through
AudioEngine.init()
if the file happens to send an emptyAudioEvent
.Additional context:
I ran the package tests in my local clone, but they fail. As I understand, this is to be expected for now because of the custom dylib depdendencies. I tried to use the library generation script from this thread but unfortunately couldn't fix the tests. I'm happy to try any alternative suggestions to help with checks.
Let me know if I missed anything please. Thanks for creating this useful runtime!